Urgent.News

What's breaking now, across thousands of outlets.

Tech

Your Chat History Is Eating the Context Window — Fix It With a Reducer

Turn nine of a support chat feels fine. Turn ninety is a different animal. Every request resends the system prompt, three agent loops of tool noise, the user's third restatement of the same bug, and yesterday's dark-mode tangent. The model does not mind. Your invoice does — and attention quality usually dies before the hard token limit. messages.TakeLast(20) in one controller is not a policy. The…

Every conversation with an AI chatbot can quickly become unwieldy. A support chat may handle nine turns without issue, but a conversation stretching to ninety turns introduces challenges. Each request brings a system prompt, three agent loops of tool noise, repeated explanations of the same issue, and tangents from the past. The AI model does not mind this complexity, but the customer's invoice certainly does, and the model's attention quality often declines before the token limit is reached. Simply taking the last twenty messages as a controller action is not a viable long-term solution.

Microsoft.Extensions.AI 10.10 (experimental MEAI001) provides tools to address these issues: IChatReducer, ReducingChatClient, and UseChatReducer. This guide explains what breaks first and how to fix it.

A reducer works like this: ReduceAsync takes an IEnumerable of ChatMessage and returns a reduced IEnumerable. The inner client receives the reduced list for both normal and streaming calls. Reducing the list keeps the model focused on what matters most.

There are four common pitfalls to watch out for. First, tool pairs can become orphaned if not handled correctly. A FunctionCallContent without its matching FunctionResultContent (or vice versa) leads to provider 400 errors. Built-in reducers exclude tool call/result messages from the reduced view, but your raw store should keep them for debugging purposes. When writing a custom reducer, test with a mixed history to ensure neither content type survives unless you explicitly opt out.

Second, counting messages when finance tracks tokens can be tricky. MessageCountingChatReducer(targetCount) keeps the first system message and up to targetCount recent non-system turns. This approach is cheap and predictable for FAQ and short troubleshooting. However, lengthy stack traces can quickly exceed the billing limit. A custom TokenAwareChatReducer estimates token usage, always keeps the first system prompt, processes messages from newest to oldest until the budget is filled, and drops tool pairs by default. The implementation for this reducer is included in the complete project.

Third, summarizing with the flagship model can create confusion. SummarizingChatReducer(summarizer, targetCount, threshold) kicks in when unsummarized non-system messages exceed targetCount + threshold. Older turns are compacted into one assistant summary, while recent turns remain unchanged. The system prompt and tool content remain untouched.

Using the flagship model for summarization can inadvertently create an additional invoice while you focus on the initial savings. Also, summarization may insert a __summary__ tag in the AdditionalProperties of boundary messages. When previewing endpoints, clone messages first to avoid unintentionally modifying the live session store.

Finally, never forget the sacred system prompt. Every reducer variant mentioned above keeps it intact. If you decide to save tokens by silencing the system prompt, you essentially have a different chat product altogether. If the system prompt alone is large, consider optimizing the prompt rather than quietly dropping it in production.

To manage all of this, use a consistent session surface across API, worker, and CLI methods. A single pipeline suffices for creating sessions, handling chat messages, and retrieving raw or reduced transcripts. Simply swap the inner client for an OpenAI, Azure, or Ollama client as needed – the reducer layer remains unchanged.

Pin Microsoft.Extensions.AI to version 10.10 and treat MEAI001 as a usable-but-evolving package. The complete working project with counting, summarizing, and token-aware reducer modes, an offline summarizer, and session APIs is available in Tech Skill Builder for $5/month (normally $10). Don't wait – grab it now before the price increases.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

I built a cross-platform Android emulator manager with Tauri 2 + Rust — no Android Studio required

I got tired of three things at once: the Android emulator CLI is tedious, Android Studio is a multi-gigabyte install for just running AVDs, and every decent alternative is either closed-source or…

  • Enmulator simplifies Android emulator management without Android Studio
  • Built with Tauri 2 (Rust backend) and React 18 frontend
  • Offers device creation, management, and headless API integration

React Performance Debugging: Find and Fix Unnecessary Re-Renders with Real Examples

Have you ever clicked a button in a React application and noticed that components you didn't touch were rendering again? Maybe a dashboard feels sluggish when updating a counter.

  • Unnecessary re-renders cause sluggish React performance
  • Four common causes: props/state changes, parent rendering, consumed context, external subscriptions
  • Memoize unstable object references with useMemo to fix re-renders

More from Thursday 15 October →