Context Window Manager
Every LLM has no memory of its own — it sees only what you send it on this call, and nothing else. The moment a conversation runs past a handful of turns, you have to decide how to manage that history yourself, or the assistant either forgets things it was just told or the cost of every call quietly balloons. This project is where you design and build that decision, not just recite it in an interview.
What you’re building
context-window-manager extends a retrieval-backed assistant (Project 3’s territory) with a
memory layer that decides, on every turn, whether to keep appending to a simple in-context buffer
or to compress older turns into a structured summary — one that explicitly tracks the user’s
goal, key decisions, open items, and stated preferences, not just a narrative recap. The same
system also draws the line between memory that’s scoped to this one conversation (episodic) and
facts that should persist across sessions (semantic) — most assistants only ever build the first
kind, which is exactly why the second kind is what makes an assistant feel like it actually knows
the user.
How a turn is handled
The two decision points — “over the summarization threshold?” and “should this fact persist across sessions?” — are exactly the two places a naive chat loop either quietly forgets something or quietly gets expensive.
Core concepts, three levels deep
1. Context window and the in-context buffer
- Definition: the context window is the fixed per-call token budget — everything you send (system prompt, history, retrieved data, current message) has to fit inside it, on every single request. The in-context buffer is the simplest possible memory strategy: append the full conversation history to every call, with zero extra setup.
- In this project: the buffer is your starting point and it works fine for short sessions — the failure mode only shows up once history grows past what fits, and it fails silently: the oldest turns get dropped with no signal to you or the model.
- Practical consequence: never let the buffer grow unbounded and unmonitored. Decide a threshold before you ship, not after a user notices the assistant “forgot” something.
2. Summarisation memory and “lost in the middle”
- Definition: summarisation memory compresses old turns into a compact structured summary once a threshold is crossed, then replaces those turns with the summary. “Lost in the middle” is a separate, related fact about attention: models recall the beginning and end of a long context more reliably than content buried in the middle — even when everything technically fits.
- In this project: these two facts together are why the summary can’t just be “a shorter version of the conversation.” If it compresses chronologically instead of preserving specific decisions, the important fact can still get buried and effectively lost, the same way it would in an un-summarized but overly long context.
- Practical consequence: design your summary format explicitly — user’s goal, decisions made, open items, stated preferences — instead of asking the model for a generic recap. A summary that only captures “what was discussed” is not doing the job.
3. Context poisoning
- Definition: a failure mode where a harmful or incorrect instruction that enters early in a conversation — through user input, not the system prompt — gets folded into a summary and then keeps propagating through every later turn, because nothing in the pipeline distinguishes it from legitimate conversation content.
- In this project: your summarization call reads raw user-turn text and produces something that gets injected back into the system context on every future turn — that’s exactly the path poisoning travels down if you’re not careful about what’s allowed to influence it.
- Practical consequence: keep system-level rules in the system message layer only, and never let summarized user content get treated as an instruction. This has to be a code-level guarantee, not a prompt-level request.
4. Episodic vs. semantic memory
- Definition: episodic memory is what happened in the current conversation — it resets at the end of the session and is what your in-context buffer and summarization both implement. Semantic memory is persistent facts about the user (stated goal, experience level, preferences) that survive across sessions, stored separately and injected as system context at the start of a new one.
- In this project: the summarization layer only ever gives you episodic memory. Semantic memory is a deliberate, separate write — extracting a durable fact and saving it somewhere that outlives this conversation object.
- Practical consequence: most chatbots only ever implement episodic memory, which is why they reset to a blank slate every session. The ones that feel like they “know you” are the ones that deliberately built the semantic layer on top — it doesn’t happen automatically.
Decision rules
| If… | Then… |
|---|---|
| Sessions are short (under ~20 turns) or stateless/one-off | Use a plain in-context buffer — zero setup, and you don’t need anything more sophisticated yet |
| History is approaching a token threshold (start around 4K tokens / a handful of turns) | Trigger summarisation — compress older turns into a structured summary, keep the most recent turns verbatim |
| A follow-up message is vague or reference-heavy (“show me something different”) | Build the retrieval query from the rolling summary plus the last 2-3 verbatim turns, not the bare message alone |
| A fact should be true of the user in every future session, not just this one | Write it to a separate semantic memory store and inject it as system context at session start — don’t rely on episodic summarization to carry it forward |
Common mistakes
- Letting the in-context buffer grow unmonitored until it silently truncates instead of deciding a threshold and summarizing before you hit it.
- Summarizing chronologically instead of structurally — a summary that just compresses “what happened” can still bury the one decision that mattered, the same way an unsummarized long context can.
- Letting raw user-turn text influence system-level behavior through an unguarded summarization pass — this is exactly how context poisoning propagates.
- Treating “use a bigger context window” as a fix for either forgetting or cost — it doesn’t address lost-in-the-middle, and it makes every call more expensive, not less.
Key concepts at a glance
| Concept | One-line definition | Why it matters for context-window-manager |
|---|---|---|
| In-context buffer | Append full history to every call, zero setup | The simplest strategy, and the one that silently fails once it overflows |
| Lost in the middle | Models attend well to the start/end of a long context, poorly to the middle | Why a summary has to preserve specific decisions, not just compress narratively |
| Context poisoning | An early bad instruction propagates through every later summary | Why system rules must stay isolated from summarized user content |
| Semantic memory | Persistent user facts injected at session start, stored separately from episodic history | The deliberate extra step that makes an assistant feel like it remembers you across sessions |
Interviewers ask 'how do you manage memory in an LLM application when conversations get long?' by default for any AI Engineer role — this project is where you build a real, defensible answer instead of a rehearsed one.