Delibera.Core 10.2.7

dotnet add package Delibera.Core --version 10.2.7
                    
NuGet\Install-Package Delibera.Core -Version 10.2.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Delibera.Core" Version="10.2.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Delibera.Core" Version="10.2.7" />
                    
Directory.Packages.props
<PackageReference Include="Delibera.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Delibera.Core --version 10.2.7
                    
#r "nuget: Delibera.Core, 10.2.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Delibera.Core@10.2.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Delibera.Core&version=10.2.7
                    
Install as a Cake Addin
#tool nuget:?package=Delibera.Core&version=10.2.7
                    
Install as a Cake Tool

Delibera

⚖️ Thoughtful AI Decisions

Collective decision making through structured AI deliberation — with RAG, pgvector, Knowledge Keeper, Operator (MCP tools), Chairman, Context Compression, AutoChunking, Dependency Injection & Execution Logging.

NuGet License: MIT .NET 10 C# 15


What is Delibera?

Delibera is a C# / .NET 10 framework that orchestrates multi-model deliberations between LLMs. Multiple AI models reason through a question across structured rounds, critique each other's answers, and a Chairman weighs the arguments to synthesise a balanced final verdict — enriched by a Knowledge Keeper backed by Qdrant or PostgreSQL/pgvector (RAG), with intelligent context compression to minimise token usage.

The name comes from deliberation — the careful weighing of evidence and viewpoints before reaching a decision. Delibera brings that discipline to AI, helping teams reach thoughtful, well-reasoned outcomes rather than single-model guesses.


✨ Features

  • 🏛️ Multi-Model Councils — orchestrate any number of LLM participants across structured debate rounds
  • ⚖️ Chairman Synthesis — a dedicated moderator opens, regulates and synthesises the final verdict
  • 📚 Knowledge Keeper (RAG) — per-round semantic retrieval with Qdrant or pgvector
  • 🐘 Qdrant + pgvector — pluggable vector stores (dedicated DB or your existing PostgreSQL)
  • 🛠️ Operator (MCP Tools) — a micro-agent that delegates tasks to MCP servers (web search, file system, Notion, PostgreSQL…) on demand during the debate
  • 🗜️ Context Compression — 4 strategies (Semantic, Deduplication, Summarization, Hybrid) save 30–70% of tokens
  • ✂️ AutoChunking — progressive disclosure of large documents across rounds, respecting model context windows
  • 💉 Dependency InjectionAddDelibera() extension for IServiceCollection with full options binding
  • 📋 Execution LoggingExecutionLog model with ExecutionLogLevel for Chairman, KK, Compression & participants
  • 📝 Microsoft.Extensions.Logging — inject your own ILogger/ILoggerFactory; every debate event is forwarded to the host's logging pipeline (in addition to the in-memory ExecutionLog collection)
  • 🛡️ Polly v8 ResilienceIHttpClientFactory + named Microsoft.Extensions.Http.Resilience retry pipelines (Delibera.Local, Delibera.Cloud, Delibera.Default) for transient HTTP failures (connection drops, 408/429/5xx, Cloudflare 524). Configure via CouncilOptions.Resilience. Custom pipelines registerable through AddDeliberaResiliencePipeline(name, build).
  • 🌐 Response Language Enforcement — force every model (participants, Chairman, Knowledge Keeper, Operator) to answer in a specific language, regardless of the prompt or retrieved context
  • Parallel Operator Requests[[OPERATOR: …]] tasks delegated within a round run in parallel, bounded by MaxDegreeOfParallelism
  • 📁 Separate File Output — export result.md, statistics.md, logs.md independently
  • 🤝 Microsoft.Extensions.AI — first-class IChatClient / IEmbeddingGenerator interop with logging & function-invocation middleware
  • 🛑 Cooperative Cancellation — every public async method accepts a CancellationToken; a host shutdown or user-initiated cancel aborts the debate mid-flight (rounds, LLM calls, MCP tools, RAG queries, file saves)
  • 🔌 Interface-First — clean abstractions for providers, factories, builders and executors
  • 🧱 Modern C# 15 — file-scoped namespaces, records, init-only properties, global usings

v10.2.6 — New Features

  • 🌊 Async Streaming CouncilICouncilExecutor.StreamDebateAsync(CancellationToken) yields each DebateRound live as it completes via an internal Channel<DebateRound> bridge. Perfect for ASP.NET Core SSE, WebSocket, Blazor, and CLI live output. DebateRound.Total + IsFinal + LastStreamedResult round metadata included.
  • 🗳️ Pluggable Vote EngineIVotingStrategy with built-in MajorityVotingStrategy, BordaCountVotingStrategy, and WeightedVotingStrategy (per-member MemberWeights). Chairman.CreateVoting(...) swaps the synthesis path for a verifiable decision tally rendered as a 🗳️ Voting Tally section in the Markdown output.
  • 💾 Debate Persistence & ResumeIDebateStore + FileDebateStore (atomic JSON write-then-rename, RetentionDays) + InMemoryDebateStore. CouncilBuilder.WithPersistence(...) saves a checkpoint after every round; ResumeFrom(debateId) continues from the last completed round after a crash or pause.
  • 🧠 Agent MemoryIAgentMemory with InMemoryAgentMemory (Jaccard similarity), QdrantAgentMemory (per-agent collection), PgVectorAgentMemory (shared table filtered by agent_name). CouncilBuilder.WithAgentMemory(...) recalls before + persists after every debate.
  • 📊 OpenTelemetry-style ObservabilityDeliberaActivitySource + DeliberaMeter with histograms, counters, and gauge for spans like delibera.council.execute, delibera.council.round, delibera.compression, delibera.member.respond. Zero-overhead when no listener is attached. CouncilBuilder.WithTelemetry(...) enables it.
  • 📋 Structured OutputIStructuredOutputSerializer + JsonSchemaOutputSerializer (uses .NET 10 JsonSchemaExporter). ICouncilExecutor.ExecuteTypedAsync<TVerdict> returns a strongly-typed verdict deserialised from the Chairman's response. One automatic retry on deserialisation failure.
  • 🔄 Adaptive Strategy SwitchingIStrategySelector + AdaptiveStrategySelector swap the debate strategy mid-flight when responses stagnate (StagnationThreshold consecutive low-diversity rounds, StagnationScore cutoff, Levenshtein fallback when no embedding provider is configured).
  • 📋 Debate Templates — 6 built-in templates (DebateTemplate.ArchitectureReview, RiskAssessment, CodeReview, ProductDecision, SecurityAudit, DataArchitecture) with pre-configured participants, personas, strategies, and chairmen. DebateTemplate.Custom() escape hatch to a raw CouncilBuilder.
  • Quick WinsDebateResult.ToHtml() + SaveToHtmlAsync() (Light/Dark themes, collapsible rounds); CouncilBuilder.WithTimeout(TimeSpan) for wall-clock debate timeout; Persona presets (Expert, DevilsAdvocate, CautiousOptimist, DataDrivenAnalyst, RiskManager, Pragmatist); CouncilBenchmark for side-by-side model comparison; WithParticipantLimit(int) safety guard.

🚀 Quick Start

1. Install

dotnet add package Delibera.Core

2. Prerequisites

ollama pull llama3.2:3b       # council member
ollama pull qwen2.5:7b        # council member / chairman
ollama pull nomic-embed-text  # embeddings (RAG)

☁️ To use Ollama Cloud instead, just pass an API key — no local models required. See the Configuration section below.

4. Run your first deliberation

using Delibera.Core.Council;
using Delibera.Core.Providers;

using var factory = new ProviderFactory();
var ollama = factory.CreateOllama("http://localhost:11434");

var result = await new CouncilBuilder()
	 .AddMember("llama3.2:3b", ollama, "Analyst")
	 .AddMember("qwen2.5:7b", ollama, "Strategist")
	 .SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
	 .WithStandardDebate()
	 .WithSystemPrompt("You are a software architecture expert.")
	 .WithUserPrompt("Microservices vs Monolith for a 5-person startup?")
	 .WithMaxRounds(4)
	 .SaveResultTo("./deliberation.md")
	 .Build()
	 .ExecuteAsync();

Console.WriteLine(result.FinalVerdict);

💉 Dependency Injection

Register all Delibera services in one line:

using Delibera.Core.DependencyInjection;

// A: with configuration binding (binds the "Delibera" section)
services.AddDelibera(configuration, "Delibera");

// B: with options delegate
services.AddDelibera(options =>
{
	 options.Strategy = "Standard";
	 options.MaxRounds = 4;
	 options.Temperature = 0.7f;
	 options.Compression.Enabled = true;
	 options.Compression.Strategy = "Hybrid";
	 options.Compression.TargetRatio = 0.5;
});

// C: defaults only
services.AddDelibera();

Resolved services:

Interface Implementation Lifetime
ILLMProviderFactory ProviderFactory Singleton
IRagProviderFactory RagProviderFactory Singleton
ICompressionFactory CompressionService Singleton
ICouncilBuilder CouncilBuilder Transient

🤝 Microsoft.Extensions.AI Interop

Delibera integrates with Microsoft.Extensions.AI through ChatClientLLMProvider and EmbeddingGeneratorProvider. Adapt any IChatClient / IEmbeddingGenerator (OpenAI, Azure OpenAI, Ollama, custom…) and use the full middleware pipeline (logging, function invocation, telemetry).

using Delibera.Core.Providers.LLM;
using Microsoft.Extensions.AI;
using OpenAI;

var openAi = new OpenAIClient(apiKey);

// IChatClient — works with any MEAI-compatible client
var chatClient = openAi.GetChatClient("gpt-4o").AsIChatClient();
var llm = new ChatClientLLMProvider(chatClient);

// IEmbeddingGenerator — for Knowledge Keeper / compression
var embeddingGen = openAi.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
var embeddings = new EmbeddingGeneratorProvider(embeddingGen);

var result = await new CouncilBuilder()
	 .AddMember("gpt-4o", llm, "Analyst")
	 .SetChairman(Chairman.CreateStandard("gpt-4o", llm))
	 .WithStandardDebate()
	 .WithUserPrompt("Should we adopt event sourcing?")
	 .Build()
	 .ExecuteAsync();

Streaming via ChatStreamAsync and DI helpers (AddDeliberaChatClient) are also included. Fully backward compatible with the existing OllamaProvider / OllamaEmbeddingProvider APIs.


🗜️ Context Compression

Automatically compress context between deliberation rounds — save 30–70% of tokens without losing meaning.

Strategy How It Works Best For
Semantic Embeds sentences, ranks by relevance to topic, keeps top-N Large knowledge contexts
Deduplication Removes semantically similar sentences across participants Multi-model debates with overlap
Summarization LLM produces a concise summary preserving key facts Maximum compression ratio
Hybrid Dedup → Semantic → Summarize pipeline Best overall quality
None Pass-through (when disabled) Debugging
using Delibera.Core.Compression;
using Delibera.Core.Providers.LLM;

var ollama = new OllamaProvider("http://localhost:11434");
var embeddings = new OllamaEmbeddingProvider(ollama, "nomic-embed-text");

var result = await new CouncilBuilder()
	 .AddMember("llama3.2:3b", ollama)
	 .SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
	 .WithCompression(CompressionStrategy.Hybrid,
		  llmProvider: ollama,
		  modelName: "llama3.2:3b",
		  embeddingProvider: embeddings)
	 .WithCompressionOptions(new CompressionOptions { TargetRatio = 0.5 })
	 .WithCompressionCache()
	 .WithUserPrompt("Analyze our architecture options...")
	 .Build()
	 .ExecuteAsync();

Console.WriteLine(result.TokenStats?.ToSummary());

✂️ AutoChunking

Automatically split large knowledge documents (contracts, reports, articles) into context-window-sized chunks distributed across debate rounds via progressive disclosure.

using Delibera.Core.Chunking;
using Delibera.Core.Knowledge;

var kb = new MarkdownKnowledgeBase();
await kb.LoadAsync("contract_200_pages.md");

var result = await new CouncilBuilder()
    .AddMember("phi3:mini", ollama, "Legal Expert")   // 4K context window
    .AddMember("llama3.2", ollama, "Business Analyst") // 128K context window
    .SetChairman(Chairman.CreateStandard("qwen2.5", ollama))
    .WithKnowledge(kb)
    .WithUserPrompt("Analyse this contract for risks to the client.")
    .WithAutoChunking()  // ← auto-chunking enabled
    .Build()
    .ExecuteAsync();
// Document is split into ~3K-token chunks (phi3:mini = 4K window)
// Chunks are progressively disclosed across rounds

Three configuration paths

// 1. Fluent API
builder.WithAutoChunking(new AutoChunkingOptions { Strategy = ChunkingStrategy.SemanticBoundary });

// 2. CouncilOptions snapshot
builder.WithOptions(new CouncilOptions { AutoChunking = new() { Enabled = true } });

// 3. Lambda
builder.WithOptions(o => { o.AutoChunking.Enabled = true; o.AutoChunking.MaxChunksPerRound = 2; });

Model Context Window Registry

var window = ModelContextWindowRegistry.GetContextWindow("llama3.2"); // → 131072
ModelContextWindowRegistry.Register("my-custom-model", 65536);

▶️ Run the demo: dotnet run --project src/Delibera.ConsoleApp -- --autochunking


📚 RAG Integration

Use a dedicated Qdrant instance or your existing PostgreSQL/pgvector database as a vector store.

using Delibera.Core.Council;
using Delibera.Core.Models;
using Delibera.Core.Providers.LLM;
using Delibera.Core.Providers.RAG;

var ollama = new OllamaProvider("http://localhost:11434");
var embeddings = new OllamaEmbeddingProvider(ollama, "nomic-embed-text");

// pgvector — just add a connection string
var ragFactory = new RagProviderFactory();
var rag = ragFactory.CreatePgVector(
	 embeddings,
	 "Host=localhost;Database=council_vectors;Username=postgres;Password=postgres");

await rag.IndexDocumentAsync("my_collection", documentText);
var results = await rag.SearchAsync("my_collection", "query", limit: 5);

// Wire into a Knowledge Keeper
var kkMember = new CouncilMember("llama3.2:3b", ollama, "Knowledge Keeper");
var keeper = new KnowledgeKeeper(rag, kkMember, "my_knowledge");
await keeper.IndexFileAsync("./docs/architecture.md");

…or use Qdrant:

var rag = ragFactory.CreateQdrant(embeddings, "localhost", 6334);

🛠️ Operator (MCP Tools)

The Operator is a lightweight micro-agent that connects the council to the outside world through MCP (Model Context Protocol) servers. It exposes whatever tools those servers provide — web search, file system access, Notion, PostgreSQL, a debate-history store, etc. — to the debate participants.

How it works

  1. The Operator connects to one or more MCP servers and discovers their tools on InitializeAsync.

  2. Participants are told (in their system prompt) what the Operator can do, and can delegate a task at any moment during the debate by writing a marker in their message:

     [[OPERATOR: search the web for the latest EU AI Act timeline and save it to Notion]]
    
  3. The Operator interprets the request with its own (cheaper) LLM model, picks and calls the right MCP tools, interprets the results, and returns a concise answer that is injected into the next round.

  4. If the council uses context compression, the Operator can reuse the same strategy to compress large tool outputs before they re-enter the debate.

All Operator interactions are recorded per round and rendered in the final Markdown report under a 🛠️ Operator Interactions block.

Quick usage

using Delibera.Core.Council;
using Delibera.Core.Models;
using Delibera.Core.Providers.LLM;

var ollama = new OllamaProvider("http://localhost:11434");

// Define the MCP servers the Operator may use
var servers = new[]
{
	 McpServerConfig.Stdio(
		  name: "everything",
		  command: "npx",
		  arguments: new[] { "-y", "@modelcontextprotocol/server-everything" }),

	 McpServerConfig.Stdio(
		  name: "filesystem",
		  command: "npx",
		  arguments: new[] { "-y", "@modelcontextprotocol/server-filesystem", "/data" }),

	 // McpServerConfig.Http(
	 //     name: "remote",
	 //     endpoint: "https://my-mcp-host.example.com/mcp",
	 //     additionalHeaders: new Dictionary<string, string> { ["Authorization"] = "Bearer <token>" }),
};

var council = new CouncilBuilder()
	 .AddMember("gpt-oss:20b",  ollama, "Optimist")
	 .AddMember("llama3.1:8b",  ollama, "Skeptic")
	 .WithChairman("gpt-oss:20b", ollama)
	 // Operator uses its own cheaper model; reuseCompression shares the council's compressor
	 .WithOperator("llama3.2:3b", ollama, servers, reuseCompression: true)
	 .WithTopic("Should we migrate the data pipeline to Kafka?")
	 .Build();

var result = await council.ExecuteAsync();

Prefer to build the Operator yourself? Pass a pre-built instance:

var @operator = new Operator(
	 new CouncilMember("llama3.2:3b", ollama, "Operator"),
	 new IMcpClient[] { new McpClientAdapter(servers[0]), new McpClientAdapter(servers[1]) },
	 compressor: null,            // optional IContextCompressor
	 compressionOptions: null);   // optional CompressionOptions

var council = new CouncilBuilder()
	 /* …members… */
	 .WithOperator(@operator)
	 .Build();

🗣️ Debate Strategies

Strategy Flow Use Case
StandardDebate Initial → Critique → Improved → Verdict General analysis
CritiqueDebate Position → Attack → Defence → Judge Hypothesis testing
ConsensusDebate Perspectives → Common Ground → Consensus → Facilitator Optimal solution search

Each strategy is implemented as an IDebateStrategy — combine with Builder, Template Method (DebateScenario) and Factory patterns (ProviderFactory, RagProviderFactory, CompressionFactory, Chairman) to compose custom flows.


📝 Logging (Microsoft.Extensions.Logging)

Delibera integrates with the standard .NET logging framework. Every debate event — Chairman opening, Knowledge Keeper queries, compression operations, Operator interactions, participant responses, errors — is forwarded to an injected ILogger (category Delibera.Core.Council) in addition to being recorded in the in-memory ExecutionLog collection and the OnLog event.

Inject your logger via the builder

using Microsoft.Extensions.Logging;

var loggerFactory = LoggerFactory.Create(builder =>
{
   builder.AddConsole();
   builder.SetMinimumLevel(LogLevel.Information);
});

var result = await new CouncilBuilder()
   .AddMember("llama3.2:3b", ollama, "Analyst")
   .SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
   .WithStandardDebate()
   .WithUserPrompt("…")
   .WithLogger(loggerFactory.CreateLogger("Delibera"))
   .Build()
   .ExecuteAsync();

Inject your logger factory via DI

services.AddDelibera(configuration, loggerFactory, "Delibera");
// Any ICouncilBuilder resolved from the container is automatically decorated with a logger.

When no ILogger is configured, Delibera falls back to the legacy behaviour: events are only captured in the DebateResult.ExecutionLogs collection and the OnLog/OnError events.


🌐 Response Language Enforcement

Force every model response (participants, Chairman, Knowledge Keeper, Operator) to be in a specific language, regardless of the language used in the prompt or retrieved RAG context.

var result = await new CouncilBuilder()
   .AddMember("llama3.2:3b", ollama, "Analyst")
   .AddMember("qwen2.5:7b", ollama, "Strategist")
   .SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
   .WithStandardDebate()
   .WithUserPrompt("Microservices vs Monolith for a 5-person startup?")
   .WithResponseLanguage("Russian")   // ← force Russian answers
   .Build()
   .ExecuteAsync();

Or via configuration:

{
  "Delibera": {
    "ResponseLanguage": "Russian"
  }
}

Delibera injects a strict directive into every system prompt:

IMPORTANT: You MUST answer exclusively in {language}. Never use any other language, regardless of the language used in the question, retrieved context, or other participants' messages.

Leave empty/null to let the model pick a language from context (legacy behaviour).


⚡ Performance — Parallel Operator Requests

When participants delegate multiple tasks to the Operator within a round (via [[OPERATOR: …]] markers), Delibera now executes them in parallel using Parallel.ForEachAsync, bounded by MaxDegreeOfParallelism.

var result = await new CouncilBuilder()
   .AddMember("llama3.2:3b", ollama, "Analyst")
   .WithOperator("llama3.2:3b", ollama, servers)
   .WithMaxDegreeOfParallelism(4)   // ← cap at 4 concurrent Operator tasks
   .Build()
   .ExecuteAsync();

Or via configuration:

{
  "Delibera": {
    "MaxDegreeOfParallelism": 4
  }
}

Set 0 (default) for unbounded parallelism — all delegated tasks in a round run concurrently.


📁 Output Files

Each deliberation can be exported as a single file or as three separate Markdown documents:

var result = await executor.ExecuteAsync();

// Single combined file
await result.SaveToMarkdownAsync("./deliberation.md");

// Or three separate files
var (resultPath, statsPath, logsPath) = await result.SaveAllAsync("./output");
// → debate_<timestamp>_result.md      (transcript + verdict)
// → debate_<timestamp>_statistics.md  (per-round token usage)
// → debate_<timestamp>_logs.md        (ExecutionLog)
File Contents
*_result.md Full deliberation transcript, rounds, and the Chairman's final verdict
*_statistics.md Token usage statistics with per-round breakdown
*_logs.md Execution logs (ExecutionLog) for Chairman, KK, compression & participants

📦 Configuration (appsettings.json)

{
  "Delibera": {
	 "Strategy": "Standard",
	 "MaxRounds": 4,
	 "Temperature": 0.7,
	 "SystemPrompt": "You are a knowledgeable AI expert participating in a council debate.",
	 "Providers": {
		"DefaultType": "Ollama",
		"DefaultEndpoint": "http://localhost:11434",
		"ApiKey": "",
		"EmbeddingModel": "nomic-embed-text"
	 },
	 "Compression": {
		"Enabled": true,
		"Strategy": "Hybrid",
		"TargetRatio": 0.5,
		"EnableCache": true,
		"MaxCacheEntries": 256
	 },
	 "Rag": {
		"Enabled": false,
		"ProviderType": "Qdrant",
		"Host": "localhost",
		"Port": 6334,
		"CollectionName": "council_knowledge"
	 },
	 "Operator": {
		"Enabled": true,
		"ModelName": "llama3.2:3b",
		"ReuseCompression": true,
		"McpServers": [
		  {
			 "Name": "filesystem",
			 "Transport": "Stdio",
			 "Command": "npx",
			 "Arguments": [ "-y", "@modelcontextprotocol/server-filesystem", "/data" ]
		  },
		  {
			 "Name": "remote",
			 "Transport": "Http",
			 "Endpoint": "https://my-mcp-host.example.com/mcp",
			 "AdditionalHeaders": { "Authorization": "Bearer <token>" }
		  }
		]
	 },
 	 "Output": {
 		"Directory": "./debate_results",
 		"SeparateFiles": true
 	 },
 	 "AutoChunking": {
 		"Enabled": true,
 		"Strategy": "SemanticBoundary",
 		"SafetyMargin": 0.15,
 		"MaxChunksPerRound": 3,
 		"EnableMapReduce": true,
 		"EnableProgressiveDisclosure": true
 	 }
  }
}

For Ollama Cloud, set Providers:DefaultEndpoint to https://api.ollama.com and put your key in Providers:ApiKey.


📦 NuGet Dependencies

Package Purpose
Microsoft.Extensions.AI IChatClient / IEmbeddingGenerator abstractions & middleware
OllamaSharp Ollama API client
Qdrant.Client Qdrant vector DB gRPC client
Npgsql / Pgvector PostgreSQL/pgvector support
ModelContextProtocol MCP client for the Operator role
Microsoft.Extensions.* Configuration, DI and Options

🛑 Cancellation Support

Every public async method in Delibera honors a CancellationToken cooperatively. The token flows from your entry point all the way down through debate rounds, chairman synthesis, LLM calls, MCP tool invocations, RAG queries and even file writes — a single cancel signal aborts the entire pipeline via OperationCanceledException (or TaskCanceledException).

1. Basic cancellation with a timeout

using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var result = await executor.ExecuteAsync(cts.Token);

2. Manual cancellation

using var cts = new CancellationTokenSource();

cts.Cancel(); // from anywhere — UI button, signal handler, other component
var result = await executor.ExecuteAsync(cts.Token);

Implement the lightweight IAppStoppingToken adapter for the host's lifetime (or use the extension directly with your own):

using Delibera.Core.Extensions;

public sealed class HostLifetimeAdapter(Microsoft.Extensions.Hosting.IHostApplicationLifetime lt)
    : IAppStoppingToken
{
    public CancellationToken ApplicationStopping => lt.ApplicationStopping;
}

// In your hosted service / minimal API:
public sealed class DebateRunner(
    ICouncilExecutor executor,
    IHostApplicationLifetime lifetime) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var adapter = new HostLifetimeAdapter(lifetime);
        var result = await executor.ExecuteAsync(adapter, stoppingToken);
        // ...
    }
}

executor.ExecuteAsync(adapter, ct) internally creates a linked CancellationTokenSource from ct + adapter.ApplicationStopping, so either a host shutdown or a caller cancel will stop the debate. The linked source is disposed in a finally block.

4. Console apps — wire Ctrl+C

using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
    e.Cancel = true;       // prevent the process from terminating
    cts.Cancel();          // signal the debate
};

var result = await executor.ExecuteAsync(cts.Token);

What gets cancelled?

When a token is signaled, Delibera stops at the nearest cooperative checkpoint and throws OperationCanceledException. Cancellable operations include:

Component CT-aware method
Top-level entry ICouncilExecutor.ExecuteAsync(ct)
Knowledge loading MarkdownKnowledgeBase.LoadAsync / LoadManyAsync / LoadDirectoryAsync / LoadTextAsync / LoadTextsAsync
LLM providers ChatAsync / ChatStreamAsync / IsAvailableAsync / ListModelsAsync / GetModelCapabilitiesAsync
RAG IRagProvider.IndexDocument / Search / GetContext, IVectorStore.Upsert / Search
Operator (MCP) IOperator.InitializeAsync / ExecuteTaskAsync, IMcpClient.Connect / ListTools / CallTool
Compression IContextCompressor.CompressAsync / CompressBatchAsync
Debate strategies IDebateStrategy.ExecuteAsync(ct) (all three strategies)
Output DebateResult.SaveToFileAsync / SaveToMarkdownAsync / SaveStatisticsAsync / SaveLogsAsync / SaveAllAsync


📄 License

MIT — Copyright © 2026 Delibera Project.

⚖️ Delibera — Thoughtful AI Decisions

Built with care for AI-powered collective intelligence

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.2.7 86 7/7/2026
10.2.6 93 7/6/2026
10.2.5 91 7/6/2026
10.2.4 101 6/30/2026
10.2.3 103 6/27/2026
10.2.2 126 6/26/2026
10.2.0 103 6/24/2026
10.1.1 110 6/19/2026
10.1.0 106 6/12/2026

v10.2.7 � Multi-Modal Council (F-06): bring images, diagrams, and documents into the debate with zero forced dependencies in Delibera.Core. Added: IFileContentReader extensibility point; built-in PlainTextFileReader (.txt/.md/.json/.xml/.cs/.yml/.csv/.html), ImageFileReader (.png/.jpg/.jpeg/.webp/.gif ? BinaryParts with MediaType), FallbackFileReader (graceful placeholder), DelegateFileContentReader (lambda adapter); FileContentReaderRegistry (per-extension, pre-populated, always returns a reader); MemberCapabilities flags enum (Text/Vision) on CouncilMember with auto-detection from model name via ModelContextWindowRegistry.SupportsVision; CouncilBuilder.WithAttachment(path)/WithFileReader(ext, reader/lambda) + AddMember with capabilities overload; CouncilExecutor reads attachments and injects text content into debate context; DI AddFileReader extension. 48 new unit tests; all 307 tests pass; no breaking changes. v10.2.6 � Nine new features: streaming, voting, persistence, agent memory, observability, structured output, adaptive strategy, templates, quick wins. v10.2.5 � OllamaProvider maxOutputTokens fix. v10.2.4 � Full CancellationToken support. v10.2.0�v10.2.3 � AutoChunking, Polly v8, parallel Operator, response language, logging, M.E.AI bridge.