Delibera.Core
10.2.7
dotnet add package Delibera.Core --version 10.2.7
NuGet\Install-Package Delibera.Core -Version 10.2.7
<PackageReference Include="Delibera.Core" Version="10.2.7" />
<PackageVersion Include="Delibera.Core" Version="10.2.7" />
<PackageReference Include="Delibera.Core" />
paket add Delibera.Core --version 10.2.7
#r "nuget: Delibera.Core, 10.2.7"
#:package Delibera.Core@10.2.7
#addin nuget:?package=Delibera.Core&version=10.2.7
#tool nuget:?package=Delibera.Core&version=10.2.7
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.
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 Injection —
AddDelibera()extension forIServiceCollectionwith full options binding - 📋 Execution Logging —
ExecutionLogmodel withExecutionLogLevelfor 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-memoryExecutionLogcollection) - 🛡️ Polly v8 Resilience —
IHttpClientFactory+ namedMicrosoft.Extensions.Http.Resilienceretry pipelines (Delibera.Local,Delibera.Cloud,Delibera.Default) for transient HTTP failures (connection drops, 408/429/5xx, Cloudflare 524). Configure viaCouncilOptions.Resilience. Custom pipelines registerable throughAddDeliberaResiliencePipeline(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 byMaxDegreeOfParallelism - 📁 Separate File Output — export
result.md,statistics.md,logs.mdindependently - 🤝 Microsoft.Extensions.AI — first-class
IChatClient/IEmbeddingGeneratorinterop 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 Council —
ICouncilExecutor.StreamDebateAsync(CancellationToken)yields eachDebateRoundlive as it completes via an internalChannel<DebateRound>bridge. Perfect for ASP.NET Core SSE, WebSocket, Blazor, and CLI live output.DebateRound.Total+IsFinal+LastStreamedResultround metadata included. - 🗳️ Pluggable Vote Engine —
IVotingStrategywith built-inMajorityVotingStrategy,BordaCountVotingStrategy, andWeightedVotingStrategy(per-memberMemberWeights).Chairman.CreateVoting(...)swaps the synthesis path for a verifiable decision tally rendered as a 🗳️ Voting Tally section in the Markdown output. - 💾 Debate Persistence & Resume —
IDebateStore+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 Memory —
IAgentMemorywithInMemoryAgentMemory(Jaccard similarity),QdrantAgentMemory(per-agent collection),PgVectorAgentMemory(shared table filtered byagent_name).CouncilBuilder.WithAgentMemory(...)recalls before + persists after every debate. - 📊 OpenTelemetry-style Observability —
DeliberaActivitySource+DeliberaMeterwith histograms, counters, and gauge for spans likedelibera.council.execute,delibera.council.round,delibera.compression,delibera.member.respond. Zero-overhead when no listener is attached.CouncilBuilder.WithTelemetry(...)enables it. - 📋 Structured Output —
IStructuredOutputSerializer+JsonSchemaOutputSerializer(uses .NET 10JsonSchemaExporter).ICouncilExecutor.ExecuteTypedAsync<TVerdict>returns a strongly-typed verdict deserialised from the Chairman's response. One automatic retry on deserialisation failure. - 🔄 Adaptive Strategy Switching —
IStrategySelector+AdaptiveStrategySelectorswap the debate strategy mid-flight when responses stagnate (StagnationThresholdconsecutive low-diversity rounds,StagnationScorecutoff, 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 rawCouncilBuilder. - ⚡ Quick Wins —
DebateResult.ToHtml()+SaveToHtmlAsync()(Light/Dark themes, collapsible rounds);CouncilBuilder.WithTimeout(TimeSpan)for wall-clock debate timeout;Personapresets (Expert,DevilsAdvocate,CautiousOptimist,DataDrivenAnalyst,RiskManager,Pragmatist);CouncilBenchmarkfor side-by-side model comparison;WithParticipantLimit(int)safety guard.
🚀 Quick Start
1. Install
dotnet add package Delibera.Core
2. Prerequisites
- .NET 10 SDK
- A running Ollama instance — local (
ollama serve) or Ollama Cloud (just an API key, no install).
3. Pull the recommended models
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
The Operator connects to one or more MCP servers and discovers their tools on
InitializeAsync.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]]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.
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);
3. ASP.NET Core / Worker Services — link to host shutdown
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 |
- 📖 Full README (architecture, design patterns, console app examples) → github.com/techbuzzz/Delibera
- 📄 Step-by-step walkthrough → docs/QuickStart.md
- 💻 Console app examples → src/Delibera.ConsoleApp
- 🤝 CONTRIBUTING.md
📄 License
MIT — Copyright © 2026 Delibera Project.
⚖️ Delibera — Thoughtful AI Decisions
Built with care for AI-powered collective intelligence
| 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.Extensions.AI (>= 10.7.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Configuration.Json (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Http (>= 10.0.9)
- Microsoft.Extensions.Http.Resilience (>= 10.7.0)
- Microsoft.Extensions.Logging (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.9)
- ModelContextProtocol (>= 1.4.0)
- Npgsql (>= 10.0.3)
- OllamaSharp (>= 5.4.25)
- Pgvector (>= 0.3.2)
- Qdrant.Client (>= 1.18.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
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.