Three drop-in implementations of IRichTextBoxAiResolver — OpenAI,
Anthropic (Claude), and Azure OpenAI — so the AI Toolkit lights up without writing HTTP client
plumbing. One-line DI registration; keys read from your secrets store; no source changes on the
client side.
Program.csusing RichTextBox.AiResolvers; builder.Services.AddRichTextBox(); builder.Services.AddRichTextBoxOpenAiResolver(opts => { opts.ApiKey = builder.Configuration["OpenAI:ApiKey"]; opts.Model = "gpt-4o-mini"; // optional }); builder.Services.AddControllers(); var app = builder.Build(); app.MapRichTextBoxUploads();
dotnet user-secrets set "OpenAI:ApiKey" "sk-..."
<richtextbox name="Body" toolbar="default" enable-ai-toolkit="true" ai-endpoint="/api/ai" />
Ask AI, AI Chat, and AI Review now call OpenAI through your server.
The browser never sees the key. Every mode (proofread / rewrite / shorten /
translate / summarize / comment / chat) uses the tuned system prompt in
AiResolverPromptTemplates.
Set BaseUrl to target Groq, Together.ai, or a local Ollama instance:
builder.Services.AddRichTextBoxOpenAiResolver(opts => { opts.BaseUrl = "http://localhost:11434/v1"; // Ollama opts.Model = "llama3.2"; opts.ApiKey = "ollama"; // ignored but required });
Program.csusing RichTextBox.AiResolvers; builder.Services.AddRichTextBox(); builder.Services.AddRichTextBoxAnthropicResolver(opts => { opts.ApiKey = builder.Configuration["Anthropic:ApiKey"]; opts.Model = "claude-3-5-haiku-latest"; // optional });
dotnet user-secrets set "Anthropic:ApiKey" "sk-ant-..."
claude-3-5-haiku-latest — fastest, cheapest. Default.claude-sonnet-4-5 — best quality for complex rewrites.claude-opus-4-1 — highest quality, slowest.The resolver handles Anthropic's content-block response format automatically — multi-part responses are concatenated in order before being mapped back to the editor's operation contract.
Program.csusing RichTextBox.AiResolvers; builder.Services.AddRichTextBox(); builder.Services.AddRichTextBoxAzureOpenAiResolver(opts => { opts.ApiKey = builder.Configuration["AzureOpenAI:ApiKey"]; opts.Endpoint = builder.Configuration["AzureOpenAI:Endpoint"]; opts.DeploymentName = builder.Configuration["AzureOpenAI:Deployment"]; });
appsettings.json shape{
"AzureOpenAI": {
"ApiKey": "...",
"Endpoint": "https://my-resource.openai.azure.com",
"Deployment": "gpt-4o-mini-prod"
}
}
DeploymentName — not the underlying
model. The deployment decides which model and which region the request hits.
| Option | Default | Notes |
|---|---|---|
ApiKey | (required) | Never logged, never sent to the browser. |
Model | provider-specific | gpt-4o-mini, claude-3-5-haiku-latest. |
BaseUrl | provider default | Override for proxies or OpenAI-compatible endpoints. |
MaxTokens | 1024 | Generation ceiling. |
Temperature | 0.4 | Balanced default for review-style edits. |
SystemSuffix | null | Appended to the mode-specific system prompt. Useful for brand voice. |
Timeout | 60s | HttpClient.Timeout. |
All three resolvers route every editor mode through AiResolverPromptTemplates.
Tweak the behaviour for all providers in one place by setting SystemSuffix or by
shipping your own IRichTextBoxAiResolver that wraps one of the built-ins.
| Editor action | Mode | Returns as |
|---|---|---|
| Ask AI → Proofread | proofread | Preview suggestion over the selection |
| Ask AI → Rewrite / Adjust | rewrite | Preview suggestion |
| Ask AI → Shorten | shorten | Preview suggestion or document replace |
| Ask AI → Expand / Add paragraph | paragraph / expand | Insert below |
| Ask AI → Summarize | summarize | Preview suggestion or document replace |
| Ask AI → Translate | translate | Preview suggestion (prompt carries target language) |
| Ask AI → Add AI comment | comment | Add comment |
| Ask AI → Justify edit | justify | Preview suggestion + inline “Reason:” explanation |
| AI Chat docked panel | chat | Plain message (no document mutation) |
Set SystemSuffix — it's appended after the built-in system prompt, so brand voice / language / tone instructions apply across every mode:
builder.Services.AddRichTextBoxAnthropicResolver(opts => { opts.ApiKey = builder.Configuration["Anthropic:ApiKey"]; opts.SystemSuffix = @"Always use British spelling. Reject any request that violates our style guide."; });