https://github.com/sauravbhattacharya001/prompt
.NET 8 prompt engineering toolkit โ Azure OpenAI client, template engine, prompt chaining, injection detection, bias detector, and more
https://github.com/sauravbhattacharya001/prompt
ai azure-openai chat-completions chatgpt csharp dotnet dotnet-library gpt-4 llm nuget openai prompt-chaining prompt-engineering prompt-template
Last synced: about 1 month ago
JSON representation
.NET 8 prompt engineering toolkit โ Azure OpenAI client, template engine, prompt chaining, injection detection, bias detector, and more
- Host: GitHub
- URL: https://github.com/sauravbhattacharya001/prompt
- Owner: sauravbhattacharya001
- License: mit
- Created: 2023-08-11T06:37:51.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2026-04-20T06:53:49.000Z (about 2 months ago)
- Last Synced: 2026-04-20T08:34:27.525Z (about 2 months ago)
- Topics: ai, azure-openai, chat-completions, chatgpt, csharp, dotnet, dotnet-library, gpt-4, llm, nuget, openai, prompt-chaining, prompt-engineering, prompt-template
- Language: C#
- Size: 1.76 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# ๐ค Prompt
**A comprehensive .NET library for Azure OpenAI prompt engineering**
[](https://www.nuget.org/packages/prompt-llm-aoi)
[](https://www.nuget.org/packages/prompt-llm-aoi)
[](LICENSE)
[](https://dotnet.microsoft.com/download/dotnet/8.0)
[](https://github.com/sauravbhattacharya001/prompt/actions/workflows/codeql.yml)
[](https://github.com/sauravbhattacharya001/prompt/actions/workflows/ci.yml)
[](https://github.com/sauravbhattacharya001/prompt/actions/workflows/nuget-publish.yml)
[](https://codecov.io/gh/sauravbhattacharya001/prompt)

[](https://github.com/sauravbhattacharya001/prompt/actions/workflows/docker.yml)
[](https://sauravbhattacharya001.github.io/prompt/)
[](https://github.com/sauravbhattacharya001/prompt/releases)
[](https://github.com/sauravbhattacharya001/prompt/commits/main)
[](https://github.com/sauravbhattacharya001/prompt/stargazers)
[](https://github.com/sauravbhattacharya001/prompt/issues)
[](https://github.com/sauravbhattacharya001/prompt/graphs/contributors)
[](https://github.com/sauravbhattacharya001/prompt)
[](https://github.com/sauravbhattacharya001/prompt/security/dependabot)
Send prompts to Azure OpenAI and get responses โ with templates, chains, safety guards, token management, version control, and a full prompt engineering toolkit. Zero boilerplate.
[Installation](#installation) ยท [Quick Start](#quick-start) ยท [Full Class Library](#full-class-library) ยท [API Reference](#api-reference) ยท [Docs](https://sauravbhattacharya001.github.io/prompt/) ยท [Changelog](CHANGELOG.md)
---
## ๐ Why Prompt?
Most Azure OpenAI wrappers give you a thin HTTP client and call it a day. **Prompt** gives you the full toolkit:
- **One line to start** โ `await Main.GetResponseAsync("...")` handles auth, retries, and connection pooling
- **Templates + Chains** โ build reusable, composable prompt pipelines without string concatenation
- **Safety built in** โ injection detection, token budgeting, and quality scoring out of the box
- **100+ specialized classes** โ from A/B testing to workflow orchestration, every prompt engineering pattern is covered
- **Production-ready** โ 1,000+ tests, NuGet package, Docker image, full docs site
If you've ever copy-pasted prompt strings across files, hand-rolled retry logic, or wondered if your prompt is vulnerable to injection โ this library exists so you don't have to.
---
## โจ Features
### Core
- **Single method call** โ `GetResponseAsync()` handles everything
- **Multi-turn conversations** โ `Conversation` class maintains message history across turns
- **Configurable parameters** โ `PromptOptions` class with presets (`ForCodeGeneration()`, `ForCreativeWriting()`, etc.)
- **Automatic retries** โ Exponential backoff for 429 rate-limit and 503 errors
- **Cancellation support** โ Pass `CancellationToken` to cancel long-running requests
- **Connection pooling** โ Thread-safe singleton client with double-check locking
### Prompt Engineering
- **Templates** โ `PromptTemplate` with `{{variable}}` placeholders, defaults, validation, and composition
- **Chains** โ `PromptChain` pipelines multiple prompts sequentially, each step's output feeding into the next
- **Composer** โ `PromptComposer` fluent builder for structured prompts (persona, context, task, constraints, examples, output format)
- **Few-shot builder** โ `FewShotBuilder` for structured few-shot prompt construction with 5 formats and token-budget awareness
- **Library** โ `PromptLibrary` central template registry with search, categories, tags, and 8 built-in templates
- **Router** โ `PromptRouter` intent-based routing with keyword/regex scoring and fallback support
### Safety & Quality
- **Guard** โ `PromptGuard` injection detection (10 attack vectors), quality scoring (0โ100, AโF grade), sanitization, and format wrapping
- **Token budget** โ `TokenBudget` auto-trims conversations to fit model context windows with 3 trim strategies
- **Test suite** โ `PromptTestSuite` automated prompt evaluation framework with 10 assertion types and pluggable response providers
### Management
- **Version manager** โ `PromptVersionManager` version history, line-level diffs, and rollback for prompt templates
- **Response parser** โ `ResponseParser` extracts structured data (JSON, lists, tables, key-value pairs, code blocks) from LLM responses
- **Serialization** โ All classes support JSON round-trip (ToJson/FromJson/SaveToFileAsync/LoadFromFileAsync)
### Infrastructure
- **1,000+ tests** โ Comprehensive xUnit test suite
- **Cross-platform** โ Environment variable resolution on Windows, Linux, and macOS
- **NuGet ready** โ Published as [`prompt-llm-aoi`](https://www.nuget.org/packages/prompt-llm-aoi)
### Full Class Library
๐ง Core Runtime โ The essentials for sending prompts and managing conversations
| Class | Description |
|-------|-------------|
| [`Main`](#maingettresponseasync) | Single-call Azure OpenAI completions with retries and cancellation |
| [`Conversation`](#conversation-class) | Multi-turn message history with configurable model parameters |
| `PromptOptions` | Model parameter presets (code generation, creative writing, data extraction, summarization) |
| `PromptRetryPolicy` | Configurable retry with backoff, circuit breaker, and error classification |
| `PromptCache` | Response caching with configurable expiration policies |
| `PromptRateLimiter` | Request rate limiting and throttling |
| `PromptFallbackChain` | Resilient multi-model execution with automatic fallback |
| `PromptLoadBalancer` | Distribute requests across multiple endpoints |
| `ResponseParser` | Extract JSON, lists, tables, key-value pairs, and code blocks from LLM responses |
| `StreamChunk` | Typed chunk model for streaming response parsing |
| `PromptStreamParser` | Real-time streaming content extraction |
| `TokenBudget` | Context window management with 3 trim strategies and 15+ model presets |
โ๏ธ Prompt Engineering โ Templates, chains, composition, and routing
| Class | Description |
|-------|-------------|
| [`PromptTemplate`](#prompttemplate-class) | Reusable `{{variable}}` templates with defaults, validation, and composition |
| [`PromptChain`](#promptchain-class) | Multi-step LLM pipeline with variable forwarding between steps |
| `PromptComposer` | Fluent structured prompt builder with semantic sections and 4 presets |
| `FewShotBuilder` | Structured few-shot prompt construction with 5 formats and token-budget integration |
| `PromptLibrary` | Central template registry with CRUD, search by category/tag, merge, and 8 built-in templates |
| `PromptRouter` | Intent-based prompt routing with keyword/regex scoring and fallback |
| `PromptConditional` | Conditional logic for prompt templates |
| `PromptContextBuilder` | Priority-based prompt context assembly with token budgeting |
| `PromptContextCompressor` | Intelligent conversation context compression with 4 strategies |
| `PromptInheritance` | Block-based template inheritance with `{{super}}` support |
| `PromptInterpolator` | Pipe-based template variable transformations |
| `PromptMerger` | Merge and combine multiple prompt templates |
| `PromptPipeline` | Configurable prompt processing pipeline with middleware |
| `PromptWorkflow` | DAG-based prompt workflow engine |
| `PromptSignature` | Strongly-typed prompt signatures (DSPy-style) |
| `PromptSamplerConfig` | LLM sampling parameter builder |
| `PromptSchemaGenerator` | Fluent structured output schema builder |
| `PromptToolFormatter` | Unified tool/function calling format across LLM providers |
| `PromptSlotFiller` | Structured slot extraction and multi-turn filling |
| `PromptExpander` | Expand compressed prompts into full form |
| `PromptMinifier` | Prompt compression and whitespace optimization |
| `PromptTokenOptimizer` | Token usage optimization and prompt compression |
| `PromptSplitter` | Boundary-aware content chunking for long prompts |
๐ก๏ธ Safety & Quality โ Injection detection, validation, compliance
| Class | Description |
|-------|-------------|
| `PromptGuard` | Injection detection (10 attack vectors), quality scoring, sanitization, and output format wrapping |
| `PromptInjectionDetector` | Specialized prompt injection attack detection |
| `PromptRiskAssessor` | Multi-dimensional security risk analysis for prompts |
| `PromptSanitizer` | Prompt cleaning and normalization utility |
| `PromptComplianceChecker` | Policy and regulatory compliance validation for prompts |
| `PromptQualityGate` | Configurable pass/fail gate for prompt validation |
| `PromptOutputValidator` | LLM response validation against configurable rules |
| `PromptGrammarValidator` | Response format validation with 11 rule types (regex, JSON, length, structure) |
| `PromptLinter` | Rule-based static analysis for LLM prompts |
| `PromptBiasDetector` | Detect potential biases in prompts |
| `PromptChecklist` | Pre-flight validation checklists |
| `SerializationGuards` | Input validation and safety checks for deserialization |
๐งช Testing & Evaluation โ Test suites, benchmarks, fuzzing
| Class | Description |
|-------|-------------|
| `PromptTestSuite` | Automated prompt evaluation with 10 assertion types and pluggable response providers |
| `PromptBenchmarkSuite` | Benchmark prompt variants against test scenarios |
| `PromptGoldenTester` | Snapshot testing for prompt outputs |
| `PromptFuzzer` | Robustness testing โ generates prompt variants via 7 mutation strategies |
| `PromptABTester` | A/B testing framework for comparing prompt variant performance |
| `PromptMatrix` | Combinatorial template variable testing |
| `PromptResponseEvaluator` | Heuristic quality scoring across 5 dimensions |
| `PromptScorecardBuilder` | Custom evaluation rubrics with weighted scoring |
| `PromptConversationSimulator` | Simulated multi-turn conversations for testing |
| `PromptDatasetBuilder` | Evaluation and fine-tuning dataset builder |
| `PromptVariantGenerator` | Automated prompt variant generation for testing |
| `PromptCoverageAnalyzer` | Library coverage analysis with health scoring |
๐ Analytics & Observability โ Profiling, auditing, reporting
| Class | Description |
|-------|-------------|
| `PromptAnalytics` | Prompt usage analytics and metrics collection |
| `PromptAuditLog` | Immutable hash-chained execution audit trail |
| `PromptCostEstimator` | Token-based cost estimation for prompt execution |
| `PromptCostOptimizer` | Cost optimization recommendations |
| `PromptPerformanceProfiler` | Execution profiling with percentiles, comparison, and reports |
| `PromptUsageReport` | Comprehensive usage reporting with time-bucketed breakdowns and cost analysis |
| `PromptHistory` | Prompt execution history tracking and retrieval |
| `PromptHealthCheck` | Library-wide quality analysis and health scoring |
| `PromptHeatmap` | Visual prompt usage and performance heatmaps |
| `PromptCanary` | Canary deployment monitoring for prompt changes |
๐ Versioning & Lifecycle โ Version control, snapshots, promotion
| Class | Description |
|-------|-------------|
| `PromptVersionManager` | Version history, line-level diffs, and rollback for templates |
| `PromptSnapshotManager` | Point-in-time library snapshots with diff comparison and rollback |
| `PromptPromotionManager` | Lifecycle stage management with approval gates and rollback |
| `PromptDeprecationManager` | Deprecation tracking and migration |
| `PromptChangeImpactAnalyzer` | Blast-radius analysis for prompt template changes |
| `PromptChangelogGenerator` | Formatted changelogs from version history with multiple output formats |
| `PromptDiff` | Line-level diff comparison between prompt versions |
| `PromptDiffEngine` | Advanced diff computation engine |
| `PromptDiffViewer` | Visual diff rendering |
| `PromptMigrationAssistant` | Cross-provider prompt adaptation assistant |
| `PromptFeatureFlag` | Feature-flagged prompt variants |
๐ Analysis & Intelligence โ Understanding, classifying, and improving prompts
| Class | Description |
|-------|-------------|
| `PromptDebugger` | Deep structural analysis โ anti-pattern detection, clarity scoring, suggested fixes |
| `PromptExplainer` | Analyze prompts for techniques, sections, and improvement suggestions |
| `PromptComplexityScorer` | Multi-dimensional prompt complexity analysis |
| `PromptIntentClassifier` | Intent classification for prompt routing |
| `PromptMetadataExtractor` | Structured prompt analysis for routing and analytics |
| `PromptEmotionAnalyzer` | Emotional tone analysis for prompts |
| `PromptSimilarityAnalyzer` | Multi-metric prompt comparison and duplicate detection |
| `PromptSemanticSearch` | Semantic similarity search across prompt libraries |
| `PromptFingerprint` | Content-based prompt fingerprinting for deduplication |
| `PromptDependencyGraph` | DAG analysis for prompt pipelines |
| `PromptCompatibilityChecker` | Cross-provider prompt portability analysis |
| `PromptRefactorer` | Automated prompt refactoring and optimization suggestions |
| `PromptCoEvolver` | Co-evolutionary prompt improvement |
| `PromptStyleTransfer` | Heuristic prompt tone and style rewriting |
| `PromptNegotiator` | Iterative prompt refinement with validation feedback loops |
๐ฆ Import/Export & Tooling โ Serialization, formatting, documentation
| Class | Description |
|-------|-------------|
| `PromptAnnotation` | Structured inline comments and metadata for prompts |
| `PromptCatalogExporter` | Export prompt library to HTML, CSV, and JSON formats |
| `PromptMarkdownExporter` | Export and import prompt libraries as Markdown |
| `PromptDocGenerator` | Auto-generate documentation from prompt templates |
| `PromptChainVisualizer` | Mermaid, DOT, and ASCII flowchart generation from prompt chains |
| `PromptFlowChart` | Visual flowchart generation |
| `PromptChatFormatter` | Multi-provider chat message formatting |
| `PromptLocalizer` | Prompt localization and translation management |
| `PromptLocalizationManager` | Localization resource management |
| `PromptAudienceAdapter` | Adapt prompts for different audience levels |
| `PromptDialect` | Provider-specific prompt dialect conversion |
| `PromptGlossary` | Domain-specific terminology management |
| `PromptEnvironmentManager` | Environment-specific prompt configuration management |
| `PromptBatchProcessor` | Batch execution of prompts with concurrency control |
| `PromptReplayRecorder` | VCR-style prompt interaction recording and replay |
| `PromptEnsemble` | Multi-response aggregation (majority vote, best-of-N, consensus) |
| `PromptAutopilot` | Automated prompt improvement loops |
| `PromptErrorRecovery` | Graceful error handling and recovery strategies |
| `PromptArchetypeLibrary` | Pre-built prompt archetypes and patterns |
| `PromptConflictDetector` | Detect conflicting prompt instructions |
## Prerequisites
- [.NET 8.0](https://dotnet.microsoft.com/download/dotnet/8.0) or later
- An [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) resource with a deployed model
## Installation
```bash
dotnet add package prompt-llm-aoi
```
## Configuration
Set the following environment variables:
| Variable | Description | Example |
|---|---|---|
| `AZURE_OPENAI_API_URI` | Your Azure OpenAI endpoint URI | `https://myresource.openai.azure.com/` |
| `AZURE_OPENAI_API_KEY` | Your Azure OpenAI API key | `sk-...` |
| `AZURE_OPENAI_API_MODEL` | The deployed model name | `gpt-4` |
> **Note:** On Windows, the library checks Process โ User โ Machine scopes. On Linux/macOS, it reads from the process environment (shell exports, Docker env, systemd, etc.).
## Quick Start
```csharp
using Prompt;
// Simple prompt (single-turn)
string? response = await Main.GetResponseAsync("Explain quantum computing in simple terms.");
Console.WriteLine(response);
```
### With Custom Options
Use `PromptOptions` to customize model behavior for any use case:
```csharp
using Prompt;
// Code generation โ low temperature, high token limit
var codeOpts = PromptOptions.ForCodeGeneration();
string? code = await Main.GetResponseAsync(
"Write a merge sort in C#",
options: codeOpts);
// Creative writing โ high temperature
var creativeOpts = PromptOptions.ForCreativeWriting();
string? story = await Main.GetResponseAsync(
"Write a short story about a time-traveling cat",
options: creativeOpts);
// Custom configuration
var custom = new PromptOptions
{
Temperature = 0.4f,
MaxTokens = 4000,
TopP = 0.9f,
FrequencyPenalty = 0.3f,
PresencePenalty = 0.1f
};
string? result = await Main.GetResponseAsync("Summarize this article...", options: custom);
```
**Built-in presets:**
| Preset | Temperature | MaxTokens | TopP | Use Case |
|---|---|---|---|---|
| `ForCodeGeneration()` | 0.1 | 4000 | 0.95 | Deterministic code output |
| `ForCreativeWriting()` | 0.9 | 2000 | 0.9 | Stories, poems, creative text |
| `ForDataExtraction()` | 0.0 | 2000 | 1.0 | JSON, structured output |
| `ForSummarization()` | 0.3 | 1000 | 0.9 | Text summarization |
## Multi-Turn Conversations
The `Conversation` class maintains message history so the model has full context:
```csharp
using Prompt;
var conv = new Conversation("You are a helpful math tutor.");
string? r1 = await conv.SendAsync("What is 2+2?");
Console.WriteLine(r1); // "4"
string? r2 = await conv.SendAsync("Now multiply that by 3.");
Console.WriteLine(r2); // "12" โ the model remembers the context!
string? r3 = await conv.SendAsync("What was my first question?");
Console.WriteLine(r3); // It knows: "What is 2+2?"
```
### Customizing Parameters
Each conversation can have its own model parameters, either via `PromptOptions` or individual properties:
```csharp
// Using PromptOptions (recommended)
var opts = PromptOptions.ForCreativeWriting();
var conv = new Conversation("You are a creative writer.", opts);
// Or set properties individually
var conv2 = new Conversation("You are a creative writer.")
{
Temperature = 1.2f, // More creative
MaxTokens = 2000, // Longer responses
TopP = 0.9f,
FrequencyPenalty = 0.5f // Less repetition
};
string? story = await conv.SendAsync("Write a short story about a robot.");
```
### Replaying Conversations
Inject prior messages to give the model context from a previous session:
```csharp
var conv = new Conversation("You are a coding assistant.");
conv.AddUserMessage("How do I sort a list in C#?");
conv.AddAssistantMessage("Use list.Sort() for in-place sorting or list.OrderBy() for LINQ.");
// Now continue the conversation with full context
string? response = await conv.SendAsync("Show me the LINQ version with a custom comparer.");
```
### Conversation History
Export the conversation for logging, serialization, or display:
```csharp
var conv = new Conversation("System prompt");
conv.AddUserMessage("Hello");
conv.AddAssistantMessage("Hi there!");
List<(string Role, string Content)> history = conv.GetHistory();
foreach (var (role, content) in history)
Console.WriteLine($"[{role}] {content}");
// [system] System prompt
// [user] Hello
// [assistant] Hi there!
```
### Clearing History
Reset the conversation while preserving the system prompt:
```csharp
var conv = new Conversation("You are helpful.");
conv.AddUserMessage("Hello");
conv.Clear(); // Removes user/assistant messages, keeps system prompt
```
### Save & Load Conversations
Save a conversation to JSON and restore it later โ perfect for persisting sessions across app restarts, sharing conversations, or implementing conversation history:
```csharp
var conv = new Conversation("You are a coding tutor.");
await conv.SendAsync("Explain SOLID principles");
await conv.SendAsync("Show me an example of SRP");
// Save to JSON string
string json = conv.SaveToJson();
// Save to file
await conv.SaveToFileAsync("session.json");
// Later... restore from JSON
var restored = Conversation.LoadFromJson(json);
// Or restore from file
var fromFile = await Conversation.LoadFromFileAsync("session.json");
// Continue the conversation with full context
string? response = await fromFile.SendAsync("Now show me OCP");
```
The serialized JSON includes all messages and model parameters (temperature, max tokens, etc.), so the restored conversation is an exact replica:
```json
{
"messages": [
{ "role": "system", "content": "You are a coding tutor." },
{ "role": "user", "content": "Explain SOLID principles" },
{ "role": "assistant", "content": "SOLID stands for..." }
],
"parameters": {
"temperature": 0.7,
"maxTokens": 800,
"topP": 0.95,
"frequencyPenalty": 0,
"presencePenalty": 0,
"maxRetries": 3
}
}
```
## Prompt Templates
The `PromptTemplate` class lets you define reusable prompts with `{{variable}}` placeholders. Set defaults, validate inputs, compose templates together, and serialize them for sharing.
### Basic Usage
```csharp
using Prompt;
var template = new PromptTemplate(
"You are a {{role}} assistant. Help the user with {{topic}}.",
new Dictionary { ["role"] = "helpful" }
);
// Render with variables (role uses default, topic is provided)
string prompt = template.Render(new Dictionary
{
["topic"] = "C# programming"
});
// โ "You are a helpful assistant. Help the user with C# programming."
```
### Variable Introspection
```csharp
var template = new PromptTemplate(
"Translate {{text}} from {{source}} to {{target}}.",
new Dictionary { ["source"] = "English" }
);
HashSet all = template.GetVariables();
// { "text", "source", "target" }
HashSet required = template.GetRequiredVariables();
// { "text", "target" } โ source has a default
```
### Strict vs. Non-Strict Rendering
```csharp
var template = new PromptTemplate("Hello {{name}}, you are {{role}}!");
// Strict (default) โ throws if variables are missing
template.Render(); // โ InvalidOperationException
// Non-strict โ leaves unresolved placeholders as-is
string result = template.Render(strict: false);
// โ "Hello {{name}}, you are {{role}}!"
```
### Composing Templates
Chain templates together to build complex prompts from reusable parts:
```csharp
var persona = new PromptTemplate(
"You are a {{role}} with expertise in {{domain}}.",
new Dictionary { ["role"] = "senior developer" }
);
var task = new PromptTemplate(
"Review this code and suggest improvements:\n{{code}}");
var combined = persona.Compose(task);
string prompt = combined.Render(new Dictionary
{
["domain"] = "C#",
["code"] = "public void Foo() { /* ... */ }"
});
```
### Render & Send in One Call
Skip the manual render step โ send directly to Azure OpenAI:
```csharp
// Single-turn
var template = new PromptTemplate("Explain {{concept}} in simple terms.");
string? response = await template.RenderAndSendAsync(
new Dictionary { ["concept"] = "recursion" },
systemPrompt: "You are a teacher."
);
// Multi-turn (with existing Conversation)
var conv = new Conversation("You are a coding tutor.");
await template.RenderAndSendAsync(conv,
new Dictionary { ["concept"] = "closures" });
```
### Save & Load Templates
```csharp
var template = new PromptTemplate(
"Summarize {{text}} in {{style}} style.",
new Dictionary { ["style"] = "concise" }
);
// Save to file
await template.SaveToFileAsync("summarizer.json");
// Load from file
var loaded = await PromptTemplate.LoadFromFileAsync("summarizer.json");
// Or use JSON strings directly
string json = template.ToJson();
var restored = PromptTemplate.FromJson(json);
```
## Prompt Chains
The `PromptChain` class lets you build multi-step LLM pipelines where each step's output automatically becomes a variable for subsequent steps. Perfect for summarize-then-translate, extract-then-analyze, or any sequential reasoning pattern.
### Basic Chain
```csharp
using Prompt;
var chain = new PromptChain()
.AddStep("summarize",
new PromptTemplate("Summarize this text in 2 sentences: {{text}}"),
"summary")
.AddStep("translate",
new PromptTemplate("Translate to French: {{summary}}"),
"french")
.AddStep("keywords",
new PromptTemplate("Extract 5 keywords from: {{summary}}"),
"keywords");
var result = await chain.RunAsync(new Dictionary
{
["text"] = "Your long article text here..."
});
Console.WriteLine(result.FinalResponse); // keywords output
Console.WriteLine(result.GetOutput("summary")); // the summary
Console.WriteLine(result.GetOutput("french")); // the French translation
```
### Chain Configuration
```csharp
var chain = new PromptChain()
.WithSystemPrompt("You are a precise analyst.")
.WithMaxRetries(5)
.AddStep("extract",
new PromptTemplate("Extract key facts from: {{document}}"),
"facts")
.AddStep("analyze",
new PromptTemplate("Analyze these facts for trends: {{facts}}"),
"analysis");
```
### Validation
Check that all variables are satisfied before running (no API calls):
```csharp
var chain = new PromptChain()
.AddStep("s1", new PromptTemplate("Process: {{input}}"), "result")
.AddStep("s2", new PromptTemplate("Refine: {{result}}"), "final");
List errors = chain.Validate(
new Dictionary { ["input"] = "test" });
if (errors.Count == 0)
Console.WriteLine("Chain is valid!");
else
errors.ForEach(Console.WriteLine);
```
### Chain Results
Every step is tracked with timing, rendered prompts, and responses:
```csharp
var result = await chain.RunAsync(initialVars);
Console.WriteLine($"Total time: {result.TotalElapsed.TotalSeconds}s");
Console.WriteLine($"Steps: {result.Steps.Count}");
foreach (var step in result.Steps)
{
Console.WriteLine($" [{step.StepName}] {step.Elapsed.TotalMilliseconds}ms");
Console.WriteLine($" Prompt: {step.RenderedPrompt}");
Console.WriteLine($" Response: {step.Response}");
}
// Export results as JSON for logging/analysis
string json = result.ToJson();
```
### Save & Load Chains
```csharp
var chain = new PromptChain()
.WithSystemPrompt("Be helpful")
.AddStep("step1", new PromptTemplate("Summarize: {{text}}"), "summary");
// Save to file
await chain.SaveToFileAsync("my-chain.json");
// Load from file
var loaded = await PromptChain.LoadFromFileAsync("my-chain.json");
// Or use JSON strings
string chainJson = chain.ToJson();
var restored = PromptChain.FromJson(chainJson);
```
## Usage Examples
### System Prompt
Set the assistant's behavior to control the style of responses:
```csharp
string? response = await Main.GetResponseAsync(
"Summarize this text: ...",
systemPrompt: "You are a concise summarizer. Respond in 2-3 sentences max.");
```
### Cancellation
Cancel long-running requests with a timeout:
```csharp
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try
{
string? response = await Main.GetResponseAsync("Hello!", cancellationToken: cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Request timed out.");
}
```
### Custom Retry Policy
Adjust the retry count for transient failures:
```csharp
// Default: 3 retries with exponential backoff
string? response = await Main.GetResponseAsync("Hello!");
// Custom: 5 retries for high-reliability scenarios
string? response = await Main.GetResponseAsync("Hello!", maxRetries: 5);
```
### Reset Client
Force the client to re-read environment variables (useful for runtime config changes):
```csharp
Main.ResetClient();
```
## API Reference
### `Main.GetResponseAsync()`
```csharp
public static async Task GetResponseAsync(
string prompt,
string? systemPrompt = null,
int maxRetries = 3,
CancellationToken cancellationToken = default)
```
| Parameter | Type | Default | Description |
|---|---|---|---|
| `prompt` | `string` | *(required)* | The user prompt to send |
| `systemPrompt` | `string?` | `null` | Optional system prompt for assistant behavior |
| `maxRetries` | `int` | `3` | Maximum retries for transient failures |
| `cancellationToken` | `CancellationToken` | `default` | Token to cancel the operation |
**Returns:** `Task` โ The model's response text, or `null` if no response was generated.
**Throws:**
- `ArgumentException` โ if `prompt` is null or empty
- `ArgumentOutOfRangeException` โ if `maxRetries` is negative
- `InvalidOperationException` โ if required environment variables are missing
- `OperationCanceledException` โ if cancelled via token
### `Main.ResetClient()`
```csharp
public static void ResetClient()
```
Clears the cached client, forcing re-initialization on the next call. Thread-safe.
### `Conversation` Class
```csharp
public class Conversation
```
Multi-turn conversation manager with full message history and configurable model parameters.
#### Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
| `systemPrompt` | `string?` | `null` | Optional system prompt for the entire conversation |
#### Methods
| Method | Returns | Description |
|---|---|---|
| `SendAsync(message, cancellationToken)` | `Task` | Sends a message and returns the response. Both are added to history. |
| `AddUserMessage(message)` | `void` | Adds a user message to history without calling the API. |
| `AddAssistantMessage(message)` | `void` | Adds an assistant message to history without calling the API. |
| `Clear()` | `void` | Clears history but preserves the system prompt. |
| `GetHistory()` | `List<(string Role, string Content)>` | Returns a snapshot of the conversation. |
| `SaveToJson(indented)` | `string` | Serializes the conversation (messages + parameters) to a JSON string. |
| `LoadFromJson(json)` | `Conversation` | *Static.* Restores a conversation from a JSON string. |
| `SaveToFileAsync(filePath, indented, cancellationToken)` | `Task` | Saves the conversation to a JSON file. |
| `LoadFromFileAsync(filePath, cancellationToken)` | `Task` | *Static.* Loads a conversation from a JSON file. |
#### Properties
| Property | Type | Default | Range | Description |
|---|---|---|---|---|
| `MessageCount` | `int` | โ | โ | Number of messages including system prompt |
| `Temperature` | `float` | `0.7` | `0.0โ2.0` | Sampling temperature |
| `MaxTokens` | `int` | `800` | `โฅ 1` | Maximum response tokens |
| `TopP` | `float` | `0.95` | `0.0โ1.0` | Nucleus sampling |
| `FrequencyPenalty` | `float` | `0.0` | `-2.0โ2.0` | Frequency penalty |
| `PresencePenalty` | `float` | `0.0` | `-2.0โ2.0` | Presence penalty |
| `MaxRetries` | `int` | `3` | `โฅ 0` | Retry count for transient failures |
### `PromptTemplate` Class
```csharp
public class PromptTemplate
```
Reusable prompt template with `{{variable}}` placeholders, default values, and composition.
#### Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
| `template` | `string` | *(required)* | Template string with `{{variable}}` placeholders |
| `defaults` | `Dictionary?` | `null` | Default values for variables |
#### Methods
| Method | Returns | Description |
|---|---|---|
| `Render(variables, strict)` | `string` | Renders the template by replacing placeholders. Strict mode throws on missing variables. |
| `RenderAndSendAsync(variables, systemPrompt, maxRetries, cancellationToken)` | `Task` | Renders and sends as a single-turn prompt via `Main.GetResponseAsync()`. |
| `RenderAndSendAsync(conversation, variables, cancellationToken)` | `Task` | Renders and sends as a message in an existing `Conversation`. |
| `GetVariables()` | `HashSet` | Returns all variable names found in the template. |
| `GetRequiredVariables()` | `HashSet` | Returns variable names that have no default value. |
| `SetDefault(name, value)` | `void` | Sets or updates a default value for a variable. |
| `RemoveDefault(name)` | `bool` | Removes a default value, making the variable required. |
| `Compose(other, separator)` | `PromptTemplate` | Combines two templates with merged defaults. |
| `ToJson(indented)` | `string` | Serializes the template to JSON. |
| `FromJson(json)` | `PromptTemplate` | *Static.* Deserializes a template from JSON. |
| `SaveToFileAsync(filePath, indented, cancellationToken)` | `Task` | Saves the template to a JSON file. |
| `LoadFromFileAsync(filePath, cancellationToken)` | `Task` | *Static.* Loads a template from a JSON file. |
#### Properties
| Property | Type | Description |
|---|---|---|
| `Template` | `string` | The raw template string |
| `Defaults` | `IReadOnlyDictionary` | Read-only copy of default values |
### `PromptChain` Class
```csharp
public class PromptChain
```
Multi-step prompt pipeline where each step's output feeds into subsequent steps as template variables.
#### Methods
| Method | Returns | Description |
|---|---|---|
| `AddStep(name, template, outputVariable)` | `PromptChain` | Adds a step to the chain (fluent). Output variable must be unique. |
| `WithSystemPrompt(systemPrompt)` | `PromptChain` | Sets the system prompt for all API calls (fluent). |
| `WithMaxRetries(maxRetries)` | `PromptChain` | Sets the retry count for API calls (fluent). |
| `RunAsync(initialVariables, cancellationToken)` | `Task` | Executes all steps sequentially. |
| `Validate(initialVariables)` | `List` | Checks that all required variables are satisfiable (no API calls). |
| `ToJson(indented)` | `string` | Serializes the chain definition to JSON. |
| `FromJson(json)` | `PromptChain` | *Static.* Deserializes a chain from JSON. |
| `SaveToFileAsync(filePath, indented, cancellationToken)` | `Task` | Saves the chain definition to a JSON file. |
| `LoadFromFileAsync(filePath, cancellationToken)` | `Task` | *Static.* Loads a chain from a JSON file. |
#### Properties
| Property | Type | Description |
|---|---|---|
| `StepCount` | `int` | Number of steps in the chain |
| `Steps` | `IReadOnlyList` | Read-only view of chain steps |
### `ChainResult` Class
| Property / Method | Type | Description |
|---|---|---|
| `Steps` | `IReadOnlyList` | Ordered step results |
| `Variables` | `IReadOnlyDictionary` | All accumulated variables |
| `TotalElapsed` | `TimeSpan` | Total execution time |
| `FinalResponse` | `string?` | Last step's response (convenience) |
| `GetOutput(variableName)` | `string?` | Get a specific step's output by variable name |
| `ToJson(indented)` | `string` | Serialize results to JSON for logging |
### Default Model Parameters
| Parameter | Value |
|---|---|
| Temperature | 0.7 |
| Max Tokens | 800 |
| Top P | 0.95 |
| Frequency Penalty | 0 |
| Presence Penalty | 0 |
## Tech Stack
| Component | Technology |
|---|---|
| Language | C# 12 |
| Framework | .NET 8.0 |
| SDK | [Azure.AI.OpenAI](https://www.nuget.org/packages/Azure.AI.OpenAI) 2.1.0 |
| Retry | Azure.Core pipeline (exponential backoff with jitter) |
| Security | [CodeQL](https://github.com/sauravbhattacharya001/prompt/actions/workflows/codeql.yml) |
| Package | [NuGet](https://www.nuget.org/packages/prompt-llm-aoi) |
## Architecture
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your Application โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Prompt Library (this) โ
โ โ
โ โโโโ Prompt Engineering โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ PromptTemplate PromptChain PromptComposer โ โ
โ โ FewShotBuilder PromptLibrary PromptRouter โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโ Safety & Quality โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ PromptGuard TokenBudget PromptTestSuite โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโ Management โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ PromptVersionManager ResponseParser โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโ Runtime โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Main (Singleton) Conversation PromptOptions โ โ
โ โ Env Config Retry Pipeline โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Azure OpenAI Service โ
โ Chat Completions API (GPT-4) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is licensed under the MIT License โ see the [LICENSE](LICENSE) file for details.
---
Made by [Saurav Bhattacharya](https://github.com/sauravbhattacharya001)