IndexThinking 0.21.1
dotnet add package IndexThinking --version 0.21.1
NuGet\Install-Package IndexThinking -Version 0.21.1
<PackageReference Include="IndexThinking" Version="0.21.1" />
<PackageVersion Include="IndexThinking" Version="0.21.1" />
<PackageReference Include="IndexThinking" />
paket add IndexThinking --version 0.21.1
#r "nuget: IndexThinking, 0.21.1"
#:package IndexThinking@0.21.1
#addin nuget:?package=IndexThinking&version=0.21.1
#tool nuget:?package=IndexThinking&version=0.21.1
IndexThinking
Working Memory Manager for Reasoning-capable LLMs
What It Does
IndexThinking handles the repetitive-but-hard parts of LLM integration:
- Truncation Recovery - Auto-continue when responses hit token limits
- Reasoning Extraction - Unified API for provider-specific thinking formats
- Context Tracking - Session-aware conversation with sliding window
- Token Management - Budget tracking and complexity estimation
- Content Recovery - Repair truncated JSON/code blocks
Scope
IndexThinking manages a single LLM turn, not multi-step workflows.
| IndexThinking | Agent Orchestrators |
|---|---|
| Single turn optimization | Multi-step coordination |
| Building block | Workflow controller |
| Used BY orchestrators | Uses IndexThinking |
Token counting role boundary — IndexThinking owns token counting (ITokenCounter, framework-neutral; IChatMessageTokenCounter for M.E.AI ChatMessage counting). Model metadata (context window, pricing) belongs to TokenMeter; combining the two into budget enforcement belongs to the consuming pipeline.
Quick Start
dotnet add package IndexThinking
// Register services
services.AddIndexThinkingAgents();
services.AddIndexThinkingContext();
// Wrap any IChatClient
var client = new ChatClientBuilder(innerClient)
.UseIndexThinking()
.Build(serviceProvider);
// Use normally
var response = await client.GetResponseAsync(messages);
// Access metadata
var thinking = response.GetThinkingContent();
var metrics = response.GetTurnMetrics();
Session-Aware Chat
// Context is automatically tracked and injected
var response = await client.ChatAsync("session-123", "Do that again");
Streaming with Thinking Orchestration
Streaming uses a Collect-and-Yield pattern: chunks are yielded to the caller immediately while buffered internally. After the stream completes, the buffered response is processed through the full orchestration pipeline (reasoning parsing, budget tracking, context tracking).
await foreach (var update in client.GetStreamingResponseAsync(messages))
{
// Real-time chunks arrive here
Console.Write(update.Text);
// The final update contains orchestration metadata
if (update.AdditionalProperties?.ContainsKey(ThinkingChatClient.TurnResultKey) == true)
{
var result = update.AdditionalProperties[ThinkingChatClient.TurnResultKey] as TurnResult;
Console.WriteLine($"\nTokens: {result?.Metrics.TotalTokens}");
}
}
Live reasoning separation (opt-in)
Open-source / local providers (DeepSeek, Qwen3, vLLM-served) emit reasoning inline in the text delta as
<think>…</think> rather than as a separate channel. Enable SeparateReasoningInStream to have IndexThinking
split it live — answer text arrives as TextContent, reasoning as TextReasoningContent — even when a tag is
split across chunk boundaries. No bespoke tag parser needed. Default is off (raw pass-through). Native reasoning
providers (OpenAI o-series, Anthropic, Gemini) already emit a separate channel, so this is a no-op for them.
Migration note: with separation enabled, reasoning spans are no longer part of
ChatResponseUpdate.Text(which concatenatesTextContentonly). Consumers readingupdate.Textmust switch to iteratingupdate.Contents(as below) or reasoning deltas will be silently dropped.
var options = new ThinkingChatClientOptions
{
SeparateReasoningInStream = true, // default false
// StreamingReasoningStartTag = "<think>", // defaults shown
// StreamingReasoningEndTag = "</think>",
};
await foreach (var update in client.GetStreamingResponseAsync(messages))
{
foreach (var content in update.Contents)
{
if (content is TextReasoningContent reasoning)
RenderThinking(reasoning.Text); // live "💭 thinking…" UI
else if (content is TextContent answer)
RenderAnswer(answer.Text);
}
}
Supported Providers
| Provider | Reasoning Format | Truncation Handling | Requires Activation |
|---|---|---|---|
| OpenAI | reasoning field |
length, content_filter |
No (automatic) |
| Anthropic | thinking blocks |
max_tokens, refusal |
No (automatic) |
| Google Gemini | thoughtSignature |
MAX_TOKENS, SAFETY |
No (automatic) |
| DeepSeek/Qwen | <think> tags |
OpenAI-compatible | Yes (EnableReasoning) |
| vLLM/GPUStack | Configurable tags | length |
Yes (EnableReasoning) |
Enabling Reasoning for DeepSeek/vLLM/Qwen
Some providers require explicit reasoning activation:
var options = new ThinkingChatClientOptions
{
EnableReasoning = true // Adds include_reasoning: true to requests
};
var client = new ChatClientBuilder(innerClient)
.UseIndexThinking(options)
.Build(serviceProvider);
Inline Reasoning Stripping (Automatic)
When reasoning is disabled on continuation requests (to avoid double-billing thinking tokens), open-source models sometimes output inline reasoning text instead of properly tagged content. IndexThinking automatically strips these fragments:
StripLeadingUntaggedReasoning— removes reasoning paragraphs that appear at the start of a continuation fragment (≥2 consecutive reasoning paragraphs required before stripping)StripUntaggedReasoning— removes trailing reasoning that appears after the actual answer content (requires ≥200 chars of content before the marker and ≥200 chars of trailing reasoning)
Both methods are called automatically by the continuation pipeline. They are also available as static methods on OpenSourceReasoningParser for manual use.
Documentation
License
MIT License - See LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Bcl.Memory (>= 10.0.8)
- Microsoft.Data.Sqlite (>= 10.0.8)
- Microsoft.Extensions.AI (>= 10.6.0)
- Microsoft.Extensions.AI.Abstractions (>= 10.6.0)
- Microsoft.Extensions.Caching.Abstractions (>= 10.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions (>= 10.0.8)
- Microsoft.ML.Tokenizers (>= 2.0.0)
- Microsoft.ML.Tokenizers.Data.Cl100kBase (>= 2.0.0)
- Microsoft.ML.Tokenizers.Data.O200kBase (>= 2.0.0)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 2.1.12)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on IndexThinking:
| Package | Downloads |
|---|---|
|
IronHive.Agent
IronHive Agent - Reusable agent layer for AI-powered CLI tools |
|
|
IndexThinking.SDK
Public SDK for IndexThinking - Working Memory manager for Reasoning-capable LLMs. |
|
|
PulsaLLM.SDK
Pulsa LLM SDK for language model inference |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.21.1 | 231 | 7/19/2026 |
| 0.21.0 | 178 | 7/5/2026 |
| 0.20.0 | 126 | 6/28/2026 |
| 0.19.5 | 122 | 6/26/2026 |
| 0.19.4 | 680 | 5/19/2026 |
| 0.19.3 | 397 | 3/13/2026 |
| 0.19.2 | 153 | 3/10/2026 |
| 0.19.1 | 391 | 3/9/2026 |
| 0.19.0 | 125 | 3/9/2026 |
| 0.18.5 | 203 | 3/9/2026 |
| 0.18.4 | 126 | 3/9/2026 |
| 0.18.3 | 126 | 3/9/2026 |
| 0.18.2 | 127 | 3/8/2026 |
| 0.18.0 | 202 | 3/8/2026 |
| 0.17.4 | 135 | 3/7/2026 |
| 0.17.2 | 122 | 3/7/2026 |
| 0.17.1 | 286 | 2/25/2026 |
| 0.17.0 | 221 | 2/19/2026 |
| 0.16.0 | 167 | 2/6/2026 |
| 0.15.0 | 316 | 1/20/2026 |