AI News HubLIVE
In-site rewrite6 min read

Why AI Agents Forget by Design

The article explains that major LLM APIs (OpenAI, Anthropic, Google) are stateless by default, meaning each API call is independent and the model has no inherent memory. This architectural choice forces developers to resend entire conversation histories per request, leading to high costs, latency, and performance degradation (lost-in-the-middle effect). The author identifies four production failure modes: re-explanation, knowledge loss on handoff, contradiction without resolution, and hallucination over abstention. Current mitigation patterns (prompt stuffing, fine-tuning, RAG, vector databases, etc.) are partial solutions. The temporal validity of stored facts remains an unsolved problem.

SourceHacker News AIAuthor: stantyan

You’ve seen this loop. A customer is on their fourth message to a support agent built on a frontier model. They’ve given their account number twice. They’ve explained the issue twice. The agent, helpful and polite, asks one more time: “Could you confirm your account number so I can look into this?” The model isn’t broken. The harness around it didn’t forward the earlier turn. And the API, by design, has no memory of what was said two messages ago.

This is not an edge case. It is the default behavior of every major LLM provider’s API, and it is the single biggest source of production friction in agentic systems shipping today. The reasons are architectural, not accidental, and the cost of that architecture lands somewhere on every invoice and every team’s calendar.

Why AI agents forget by design#

The OpenAI Chat Completions API, Anthropic’s Messages API, and Google’s Gemini API share one property that gets surprisingly little attention in the agent literature: they are stateless. Each call is independent. The server holds no session, no user identity, no record of prior turns. What the model “remembers” is whatever your application chose to put in the messages array for this particular request.

That is the architecture every major provider chose. It is not a limitation they apologize for in the docs. The Anthropic Messages API docs state it plainly: the API is stateless, and the client is responsible for sending the full conversational history on every call. OpenAI’s newer Responses API offers a server-side conversation object as a convenience layer, but the underlying inference call is still stateless. State is something the application maintains around the model, not something the model maintains for itself.

This decision has good engineering reasons behind it. Stateless inference scales horizontally without sticky sessions. It makes load balancing trivial. It avoids a class of memory and security bugs that plague stateful systems. And it cleanly separates the model (a function from input to output) from the application logic (which decides what input to assemble). For the provider, statelessness is the right call.

For you, the person building an agent, it means there is no “memory” feature to enable. There is only the context window you fill on each request, and whatever scaffolding you build around it.

from anthropic import Anthropic

client = Anthropic() model = "claude-sonnet-4-6"

Turn 1: the user provides their account number

response_1 = client.messages.create( model=model, max_tokens=200, messages=[ {"role": "user", "content": "My account number is ACME-48201. I can't log in."} ], ) print(response_1.content[0].text)

-> "Thanks for sharing that. To help with login issues, could you tell me..."

Turn 2: a new request, no history passed. The model has no recall.

response_2 = client.messages.create( model=model, max_tokens=200, messages=[ {"role": "user", "content": "Did the login work yet?"} ], ) print(response_2.content[0].text)

-> "I'd be happy to help. Could you share your account number so I can check?"

The second call has no idea the first call happened. To the API, these are two unrelated requests from the same key. If your agent wants the model to “remember” the account number, the agent harness has to put it back in the messages array next time. That is the entirety of how memory works at the inference layer in 2026.

The context window is not memory#

The obvious response is: “Fine, we just send all the history every time.” This is what most production agents do, and it works until it doesn’t. There are three reasons it breaks before you finish scaling.

The first is cost. Re-sending 50K tokens of conversation history every turn, across a long session, adds up fast. At Claude Sonnet 4.6 input pricing of $3 per million tokens (as of July 2026), a 100-turn session with 50K average resent context costs $15 in input alone before caching, and before counting output or any tool calls. Prompt caching blunts the cost within a session: conversation history is an append-only prefix, the textbook caching case, and cache reads run at a tenth of the base input price. But the default cache lives five minutes, which human think-time between turns routinely outlasts; the one-hour tier doubles the write cost; and no cache survives across sessions, users, or model swaps. Caching discounts the resend. It does not remove the architecture that requires the resend.

The second is latency. Bigger contexts mean longer time-to-first-token. Users notice the cost in milliseconds. Agents that run hundreds of internal turns notice it in dollars-per-task.

The third is the one most teams underestimate: long context degrades model performance. The Lost-in-the-Middle paper by Liu et al. showed that language models, including the long-context flagships, retrieve information from the beginning and end of a long context far more reliably than from the middle. A fact buried in turn 12 of a 40-turn conversation is, statistically, less likely to influence the model’s answer than the same fact pasted into the system prompt or the latest user message. The model isn’t lying when it says it doesn’t remember. It often genuinely cannot find what’s in front of it.

Bigger context windows are not a memory architecture. They are a memory workaround. The difference matters because workarounds have a ceiling, and we are approaching it. A 1M-token context window costs $3 in input to fill on Sonnet 4.6 and $10 on Claude Fable 5 as of July 2026 - per request, not per session - takes meaningful seconds to process, and still won’t reliably let the model pull a specific fact from somewhere in the middle. Stuffing more in is not the path forward.

Four production failures that lack of memory creates#

The architectural problem manifests as four distinct failure modes you will see in any agent running in front of real users for more than a few weeks.

Re-explanation. Every session starts at zero. Your most knowledgeable user, the one who has been using the product for six months, has to teach the agent who they are, what they’re working on, and what conventions they prefer, every time the chat window resets. The cost is paid in user time, user trust, and user goodwill. The cost compounds because the user’s frustration grows with each repetition, and the user is the only one who notices.

Knowledge loss on handoff. A session ends. The user walks away. Whatever the agent learned, deduced, or established during that session evaporates. The next session, with the same user or a teammate working on the same problem, begins with the same blank slate. Engineering teams using Cursor or Claude Code see this every morning: the previous day’s architectural decisions, naming conventions, and gotchas have to be re-loaded by the human into the new chat. The agent’s apparent intelligence resets with the session.

Contradiction without resolution. Today, the user tells the agent the project uses Postgres. Tomorrow, after a migration, the user says it uses DuckDB. A persistent-memory system that simply appends both facts ends up with two contradictory entries and no mechanism to decide which is current. Current vector-store-based memory implementations have no native concept of “this newer fact supersedes that older one.” Both get retrieved. The model picks based on semantic similarity, not temporal validity. The user finds out when the agent’s code targets the wrong database.

Hallucination over abstention. When the model doesn’t know something, it tends to guess plausibly rather than say “I don’t know.” This is partially a model-training problem and partially a memory-design problem: most agent memory layers have no way to distinguish “this is a confident retrieval” from “I have no relevant memory for this.” Without that distinction, the model has no reason not to confabulate. An agent that could honestly say “I don’t have a memory of your previous deployment configuration, can you remind me?” would be more useful than one that invents a plausible-sounding answer. The structural reasons why agents guess instead of saying “I don’t know” deserve separate treatment.

Each of these failures has the same root cause and four different surface symptoms. Solving them requires more than a bigger context window or a better embedding model. It requires architecture.

What teams actually do today, and why each approach falls short#

A handful of mitigation patterns have emerged. None of them solves the underlying problem, but most of them help in narrow circumstances. The honest summary:

Prompt stuffing. Cram more relevant context into the system prompt or the latest user message. Cheap, fast, breaks down past a few thousand tokens, suffers Lost-in-the-Middle.

Fine-tuning. Bake the knowledge into the weights. Powerful for stable domain knowledge, useless for facts that change weekly or are user-specific, and brutal to iterate on.

Retrieval-Augmented Generation. Pull relevant chunks from a knowledge base at inference time. Works well for documents and reference material, less well for conversational state that evolves turn-by-turn.

Vector databases. Store embedded chunks of prior conversation and retrieve by semantic similarity. The most common pattern in 2026 and the one that gets confused with memory most often. It does retrieve text. It does not give you the temporal, structural, or confidence properties that a memory layer needs. Vector databases alone aren’t enough, and treating them as a memory primitive papers over real architectural gaps.

Conversation summarization. Compress older turns into a running summary that survives in the context. Lossy by construction. The summarizer is itself a stateless model deciding what to keep and what to drop, with no awareness of what will matter three sessions from now.

Custom memory wrappers. Every team builds their own. They mostly look the same in shape, they all have edge cases the team discovers in production, and none of them are portable across applications.

Agent memory libraries. A growing category of open-source and commercial libraries that bundle the above patterns into something easier to adopt. They reduce engineering toil. They do not, individually, solve the temporal, structural, or abstention problems described above.

The platform vendors are moving too: Anthropic’s Claude Tag, launched in June 2026, gives Claude channel-scoped persistent memory inside Slack.

Most production agents use two or three of these in combination. The combination works well enough to ship a demo. It works less well by month six, when the same handful of issues show up in customer feedback over and over.

Every call to a stateless LLM API rebuilds context from whatever the application chose to keep. The model itself remembers nothing between requests.

The temporal problem nobody talks about#

Even if you solved the storage problem perfectly, you would still have a harder one underneath: temporal validity.

Suppose your memory system stores the fact “the user works at Aiven” because the user said so 18 months ago. Since then, the user has changed jobs twice. The fact is still in the store. It still embeds to roughly the same vector. It still gets retrieved when the user asks the agent about something work-related. And it is now confidently wrong.

Current agent memory systems retrieve based on semantic similarity, occasionally combined with recency weighting. Neither captures what a memory actually needs to express: not just what was learned, but when it was learned, when it was true, and whether anything since has superseded it. A real memory representation has two time dimensions, not one: when the fact entered the system, and the time range over which it was valid. Most current implementations track neither cleanly.

The consequence is a class of bugs that looks like hallucination but is actually stale-but-confident memory. The model retrieves a

[truncated for AI cost control]