# AiOptionsProvider
## Description
BitAiOptionsProvider cascades a BitAiUiOptions - the string table the components speak with, the render interval of streaming updates, what a message shows (usage, model name, timestamps, actions, sources, inline citations), the Markdown and image policies - to every AI component inside it, so a page or a region of one sets its preferences once rather than on every component. It is plumbing: it renders no element of its own, only its content. An inner provider overrides an outer one for its own content. Color scheme, accent, density and direction are not options: they come from the bit theme and the Dir of each component, exactly as for every other component of the library.
## Parameters
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| ChildContent | `RenderFragment?` | null | The content the options are provided to. It is all the provider renders: there is no element of its own around it. |
| UiOptions | `BitAiUiOptions?` | null | The options to cascade. Left unset, the options of an enclosing provider are cascaded, else the ones registered with AddBitBlazorUIAIServices (ai.ConfigureUi), else BitAiUiOptions.Default. A new instance handed in re-renders the components that read it; the options are immutable, so build one with "options with { ... }". |
## Sub Classes
### BitAiUiOptions Properties
The presentation settings every AI component reads, a sealed record: BitAiUiOptions.Default with { ShowUsage = true }. Everything here is a default, not a constraint - a component's own parameters override it. It is set for the whole app with AddBitBlazorUIAIServices(ai => ai.ConfigureUi(options => options with { ... })), for a region with a BitAiOptionsProvider, and for one chat with the UiOptions of a BitAiChat. Density is deliberately not one of the settings: the components are spaced in the units of the bit theme, so a compact chat is a region with a lower --bit-layout-density-scale (BitThemeDensityPresets.CreateCompactOverlay).
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Default | `BitAiUiOptions` | | Static: the default settings, the values of this table. |
| Markdown | `BitAiMarkdownOptions` | BitAiMarkdownOptions.Default | Which Markdown extensions the Markdown views enable - tables, strikethrough, task lists, auto links, math, footnotes, citation markers, raw HTML and the rest. A parser is built from them, and built again when other options are cascaded. |
| Images | `BitAiImagePolicy` | BitAiImagePolicy.Allow | Which images are fetched and shown - the images of Markdown, image parts, image and SVG artifacts, and the favicons of sources (a favicon only when the policy shows it outright, never as a placeholder): allowed by default; a host handling sensitive conversations can restrict them to listed hosts (AllowListedHosts), load them only on request (ClickToLoad) or block them. Script-capable URL schemes are neutralized whatever the policy. |
| RenderInterval | `TimeSpan` | TimeSpan.FromMilliseconds(50) | The minimum time between two renders of a component following a stream; every change in between is folded into the next render. The single most important performance dial: raising it reduces circuit traffic on Blazor Server, lowering it makes WebAssembly marginally smoother at a real CPU cost. |
| ShowTimestamps | `bool` | false | Shows a timestamp under each message. |
| TimeZone | `TimeZoneInfo?` | null | The time zone the times under the messages are shown in, and the days of a BitAiConversationList with no TimeZone of its own are counted in. While it is null, the zone of the browser - under Blazor Server read once the components have rendered, so a prerendered page shows the times in the zone of the server until it is interactive. |
| ShowUsage | `bool` | false | Shows the token usage under assistant messages, and the total usage of a run in the header of a BitAiAgentRunView. |
| ShowModelName | `bool` | false | Shows the model name under assistant messages. |
| ShowMessageActions | `bool` | true | Shows the copy, regenerate and feedback actions under assistant messages. |
| ShowCodeCopy | `bool` | true | Shows a copy button on code blocks. |
| ShowLineNumbers | `bool` | false | Shows line numbers in code blocks. |
| CollapseReasoning | `bool` | true | Collapses the reasoning panel until the user opens it. |
| CollapseToolCalls | `bool` | true | Collapses tool call cards until the user opens them. |
| AutoScroll | `bool` | true | Follows the newest content while streaming, until the user scrolls away. |
| VirtualizeThreshold | `int` | 60 | How many of the newest messages the message list draws once it holds more. Up to it every message is rendered, which is both simpler and faster; past it only the newest this many are - as a prerender draws them - and the older ones half that many at a time as the reader scrolls up to them, with what is being read kept in place. Back at the newest message, the pages above are let go of again. |
| SmoothStreaming | `bool` | true | Evens out bursty text so it renders at a steady rate. Read by a BitAiChat as it creates its own session (turned off, that session has no Pacing); a Session handed to the chat keeps the pacing of its own options. |
| ShowStreamingCaret | `bool` | true | Shows the caret that blinks at the end of streaming text. |
| InlineCitations | `bool` | true | Turns the bracketed numbers of the text ([1]) into interactive citation markers; off, they stay text. |
| ShowSourceList | `bool` | true | Shows the source list under a message that cites anything. |
| SubmitOnEnter | `bool` | true | Sends the prompt when Enter is pressed without a modifier. |
| MaxComposerRows | `int` | 12 | The largest number of rows the prompt textarea grows to before it scrolls. |
| Strings | `BitAiStrings` | BitAiStrings.Default | The user-facing text, for localization: a subclass of BitAiStrings that overrides what it translates. |
### BitAiStrings Properties
Every piece of user-facing text the AI components render - labels, accessible names, announcements, validation messages, and the formats of durations, sizes and token counts - kept in one replaceable object rather than scattered through markup, so that localizing the library, or changing its tone, does not mean forking components. Subclass it, override the members to translate (each is virtual), and hand an instance to BitAiUiOptions.Strings; every member left alone keeps its English. The default values below are the English expressions, written in C#.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Default | `BitAiStrings` | | Static: The default English strings. Subclass BitAiStrings and override the members to translate; every member left alone keeps its English. |
| AddItem | `string` | "Add item" | Label for adding an entry to a list field. |
| AgentCancelled | `string` | "Stopped" | Status of an agent run the user stopped. |
| AgentCompleted | `string` | "Done" | Status of an agent run that finished. |
| AgentFailed | `string` | "Failed" | Status of an agent run that failed. |
| AgentIdle | `string` | "Idle" | Status of an agent run that has not started. |
| AgentPlanning | `string` | "Planning" | Status of an agent run that is working out its steps. |
| AgentRunning | `string` | "Running" | Status of an agent run that is executing. |
| AgentStepStatus | `string` | "Not started", "In progress", "Waiting for you", "Done", "Failed", "Skipped" | AgentStepStatus(BitAiAgentStepStatus status): Where a step of an agent run stands, said to assistive technologies (the marker of the step only draws it). |
| Answer | `string` | "Answer" | Label of the button that sends a free-text answer to a waiting agent run. |
| AnswerPlaceholder | `string` | "Type your answer..." | Placeholder of the free-text answer box under a waiting agent run. |
| Approve | `string` | "Allow" | Label for approving a tool call once. |
| ApproveAlways | `string` | "Always allow" | Label for approving a tool and not being asked again. |
| ApproveTool | `string` | $"Allow {tool} to run?" | ApproveTool(string tool): Question asked when a tool call needs approval. |
| Arguments | `string` | "Arguments" | Label for the arguments section of a tool call. |
| Artifact | `string` | "Artifact" | Heading of the artifact panel. |
| AttachFile | `string` | "Attach files" | Label for the attach-file button. |
| AttachmentReadFailed | `string` | $"{fileName} could not be read." | AttachmentReadFailed(string fileName): Shown when a file could not be read. |
| Attachments | `string` | "Attachments" | Heading above an attachment list. |
| AttachmentTooLarge | `string` | $"{fileName} is too large. Files can be up to {FormatBytes(maxSize)}." | AttachmentTooLarge(string fileName, long maxSize): Shown when a file is larger than the composer accepts. |
| AttachmentTooMany | `string` | $"{fileName} was not attached. Up to {maxCount} files can be attached at once." | AttachmentTooMany(string fileName, int maxCount): Shown when more files are staged than the composer allows. |
| AttachmentTypeNotAllowed | `string` | $"{fileName} is not a supported file type." | AttachmentTypeNotAllowed(string fileName): Shown when a file is not one of the types the composer accepts. |
| BackToReference | `string` | $"Back to reference {number}" | BackToReference(int number): Accessible name of a link at the end of a footnote that leads back to where the footnote is referenced. |
| BackToReference | `string` | ordinal <= 1 ? BackToReference(number) : $"{BackToReference(number)}-{ordinal}" | BackToReference(int number, int ordinal): Accessible name of each back-link of a footnote referenced more than once, told apart by the ordinal of the reference it leads to ("Back to reference 1-2"). |
| BadResponse | `string` | "Bad response" | Label for negative feedback. |
| CachedTokens | `string` | "Cached" | Label for cached prompt tokens in the usage breakdown. |
| CalledTool | `string` | $"Used {tool}" | CalledTool(string tool): Heading of a tool call card once the tool has run. |
| CallingTool | `string` | $"Calling {tool}" | CallingTool(string tool): Heading of a tool call card before the tool has run. |
| Cancel | `string` | "Cancel" | Label for cancelling an action. |
| CharacterCount | `string` | $"{used:N0} / {max:N0}" | CharacterCount(int used, int max): The character counter under the composer when a length limit is set. |
| CharactersRemaining | `string` | remaining == 1 ? "1 character remaining" : $"{remaining:N0} characters remaining" | CharactersRemaining(int remaining): Announced when the composer text is close to its length limit. |
| CitationLabel | `string` | number is null ? $"Source: {title}" : $"Source {number}: {title}" | CitationLabel(int? number, string title): Accessible name of an inline citation marker. |
| CodeBlock | `string` | fileName ?? (language is null ? "Code" : $"{language} code") | CodeBlock(string? fileName, string? language): Accessible name of the box the code of a code block scrolls in. |
| Collapse | `string` | "Collapse" | Label for leaving full screen. |
| Commands | `string` | "Commands" | Accessible name of the slash-command menu. |
| ComponentFailed | `string` | $"'{component}' could not be rendered" | ComponentFailed(string component): Shown in place of a generated component that threw. |
| ComponentNotRegistered | `string` | $"No component named '{component}' is registered." | ComponentNotRegistered(string component): Tooltip on a generated component the application has not registered. |
| Context | `string` | "Context" | Label for the context usage meter. |
| ContextCritical | `string` | "The context window is almost full" | Shown when the context window is nearly full. |
| ContextUsage | `string` | $"{used:N0} / {window:N0} {Tokens}" | ContextUsage(long used, long window): Tooltip on the context usage meter. |
| ContextWarning | `string` | "The context window is filling up" | Shown when the context window is filling up. |
| Conversations | `string` | "Conversations" | Accessible name of the conversation list. |
| Copied | `string` | "Copied" | Confirmation shown after copying. |
| Copy | `string` | "Copy" | Label for copying content. |
| Delete | `string` | "Delete" | Label for deleting a conversation. |
| DictationFailed | `string` | $"Dictation failed: {error}" | DictationFailed(string error): Announced when dictation fails. |
| DictationStopped | `string` | "Dictation stopped" | Announced when dictation stops. |
| Dismiss | `string` | "Dismiss" | Label for dismissing a notice. |
| Download | `string` | "Download" | Label for downloading an artifact. |
| DropFiles | `string` | "Drop files to attach" | Prompt shown over the composer while a file is dragged over it. |
| Edit | `string` | "Edit" | Label for editing a message. |
| Elapsed | `string` | "Elapsed" | Accessible label for the elapsed time of a running agent. |
| EmptyBody | `string` | "Ask a question to get started." | Body shown above an empty conversation. |
| EmptyTitle | `string` | "How can I help?" | Heading shown above an empty conversation. |
| Expand | `string` | "Expand" | Label for opening an artifact full screen. |
| FieldAboveMaximum | `string` | $"{label} must be at most {maximum}." | FieldAboveMaximum(string label, double maximum): Validation message for a number above the maximum. |
| FieldBelowMinimum | `string` | $"{label} must be at least {minimum}." | FieldBelowMinimum(string label, double minimum): Validation message for a number below the minimum. |
| FieldInvalidFormat | `string` | $"{label} is not in the expected format." | FieldInvalidFormat(string label): Validation message for a value that does not match the field pattern. |
| FieldNotAboveMinimum | `string` | $"{label} must be greater than {minimum}." | FieldNotAboveMinimum(string label, double minimum): Validation message for a number at or below an exclusive minimum. |
| FieldNotADate | `string` | $"{label} must be a valid date or time." | FieldNotADate(string label): Validation message for a date or time field that does not hold one. |
| FieldNotAMultipleOf | `string` | $"{label} must be a multiple of {step}." | FieldNotAMultipleOf(string label, double step): Validation message for a number that is not a multiple of the field step. |
| FieldNotAnEmail | `string` | $"{label} must be an email address." | FieldNotAnEmail(string label): Validation message for an email field that does not hold an address. |
| FieldNotAnInteger | `string` | $"{label} must be a whole number." | FieldNotAnInteger(string label): Validation message for an integer field that holds a fraction. |
| FieldNotANumber | `string` | $"{label} must be a number." | FieldNotANumber(string label): Validation message for a numeric field that does not hold a number. |
| FieldNotAUrl | `string` | $"{label} must be a web address." | FieldNotAUrl(string label): Validation message for a URL field that does not hold a web address. |
| FieldNotBelowMaximum | `string` | $"{label} must be less than {maximum}." | FieldNotBelowMaximum(string label, double maximum): Validation message for a number at or above an exclusive maximum. |
| FieldRequired | `string` | $"{label} is required." | FieldRequired(string label): Validation message for a required field left empty. |
| FieldTooFewItems | `string` | $"{label} needs at least {minimum} items." | FieldTooFewItems(string label, int minimum): Validation message for a list with fewer entries than the field allows. |
| FieldTooLong | `string` | $"{label} must be at most {maximum} characters." | FieldTooLong(string label, int maximum): Validation message for text longer than the field allows. |
| FieldTooManyItems | `string` | $"{label} can have at most {maximum} items." | FieldTooManyItems(string label, int maximum): Validation message for a list with more entries than the field allows. |
| FieldTooShort | `string` | $"{label} must be at least {minimum} characters." | FieldTooShort(string label, int minimum): Validation message for text shorter than the field allows. |
| GenerationStopped | `string` | "Generation stopped." | The error a turn ends with when the user stopped it. |
| FormatBytes | `string` | 512 B, 12 KB, 3.4 MB, 1.2 GB | FormatBytes(long bytes): Formats a byte count for display. |
| FormatDuration | `string` | 850ms, 4.2s, 2m 5s | FormatDuration(TimeSpan duration): Formats a duration for display. |
| FormatTokens | `string` | 950, 1.6k, 2.4M | FormatTokens(long tokens): Formats a token count for display. |
| GoodResponse | `string` | "Good response" | Label for positive feedback. |
| HideDetails | `string` | "Hide details" | Label for hiding error detail that is shown. |
| IgnoredProperty | `string` | $"Ignored: {name}" | IgnoredProperty(string name): Shown for a generated property the component does not declare, so it was not passed. |
| IgnoredPropertyHint | `string` | "The component does not declare this property, so it was not passed." | Tooltip explaining an ignored generated property. |
| InputTokens | `string` | "Input" | Label for prompt tokens in the usage breakdown. |
| JsonArrayItem | `string` | $"[{index}]" | JsonArrayItem(int index): Accessible name of the toggle of an object or array that is an entry of an array of a JSON tree, by its zero-based position as JSON counts it. |
| JsonRoot | `string` | "Root" | Accessible name of the toggle of the outermost object or array of a JSON tree, which has no key. |
| Listening | `string` | "Listening" | Announced while dictation is running. |
| ListItem | `string` | $"{label} {index}" | ListItem(string label, int index): Accessible name of one entry of a list field - the group of fields of an entry of objects, the input of an entry of values - and the label its validation messages name; index is one-based. |
| LoadImage | `string` | $"Load image: {description}" | LoadImage(string description): Label of the click-to-load placeholder shown for an image the image policy did not load automatically. |
| Mentions | `string` | "Mentions" | Accessible name of the mention menu. |
| MissingProperty | `string` | $"'{name}' is required by '{component}'" | MissingProperty(string name, string component): Shown for a property a generated component requires that the model did not supply. |
| Model | `string` | "Model" | Label for the model picker. |
| ModelDeprecated | `string` | $"{name} (deprecated)" | ModelDeprecated(string name): Label of a deprecated model in the picker. |
| MonthGroup | `string` | date.ToString("MMMM yyyy", CultureInfo.CurrentCulture) | MonthGroup(DateTime date): Group heading for older conversations, one per calendar month. |
| NewConversation | `string` | "New conversation" | Label for starting a new conversation. |
| OtherModels | `string` | "Other" | Group heading in the model picker for models with neither a family nor a provider. |
| OutputTokens | `string` | "Output" | Label for completion tokens in the usage breakdown. |
| Plan | `string` | "Plan" | Heading of an agent run panel. |
| PreviousSevenDays | `string` | "Previous 7 days" | Group heading for conversations updated in the last week. |
| PreviousThirtyDays | `string` | "Previous 30 days" | Group heading for conversations updated in the last month. |
| PromptPlaceholder | `string` | "Send a message..." | Placeholder in the prompt composer. |
| ReasonedFor | `string` | $"Thought for {FormatDuration(duration)}" | ReasonedFor(TimeSpan duration): Title of the reasoning panel once finished. |
| Reasoning | `string` | "Reasoning" | Title of the collapsed reasoning panel, and the accessible name of the box its text scrolls in. |
| ReasoningTokens | `string` | "Reasoning" | Label for reasoning tokens in the usage breakdown. |
| Regenerate | `string` | "Regenerate" | Label for regenerating a response. |
| Reject | `string` | "Decline" | Label for rejecting a tool call. |
| Remove | `string` | "Remove" | Label for removing an attachment. |
| RemoveItem | `string` | $"Remove {label} {index}" | RemoveItem(string label, int index): Accessible label for removing one entry of a list field. |
| RendererFailed | `string` | $"The renderer for '{name}' failed" | RendererFailed(string name): Shown in place of content whose custom renderer threw. |
| RenderFailed | `string` | "This content could not be rendered" | Shown in place of content whose renderer threw. |
| RequestTimedOut | `string` | "The request timed out." | The error a turn ends with when it ran out of the session's time (BitAiChatSessionOptions.Timeout). |
| Result | `string` | "Result" | Label for the result section of a tool call. |
| Retry | `string` | "Try again" | Label for retrying after a failure. |
| RetryIn | `string` | $"Try again in {FormatDuration(wait)}." | RetryIn(TimeSpan wait): Shown under an error that can be retried after a delay. |
| Save | `string` | "Save" | Label for saving an edit. |
| ScrollToLatest | `string` | "Scroll to latest" | Label on the button that scrolls to the newest message. |
| Send | `string` | "Send" | Accessible label for the send button. |
| ShowDetails | `string` | "Show details" | Label for showing error detail. |
| SomethingWentWrong | `string` | "Something went wrong" | Heading of an error panel. |
| Sources | `string` | "Sources" | Heading above the list of sources. |
| StartDictation | `string` | "Dictate" | Label for the voice input button. |
| StepsCompleted | `string` | $"{done} / {total}" | StepsCompleted(int done, int total): The count of the steps of an agent run that have finished successfully, beside its progress bar. |
| Stop | `string` | "Stop" | Label for the button that stops generation. |
| StopDictation | `string` | "Stop dictation" | Label shown while dictation is active. |
| Submit | `string` | "Submit" | Default label on a form's submit button. |
| Submitted | `string` | "Submitted" | Shown in place of a form's actions once it has been submitted. |
| Table | `string` | "Table" | Accessible name of the box a table scrolls in sideways: a data table given no name of its own, and a table of Markdown. |
| Thinking | `string` | "Thinking" | Shown while the model is working but has produced nothing yet. |
| TimeToFirstToken | `string` | "Time to first token" | Name of the time to the first token in the token usage readout, read to assistive technologies before the duration the readout shows bare. |
| Today | `string` | "Today" | Group heading for conversations updated today. |
| Tokens | `string` | "tokens" | Label for the token usage readout. |
| TokensPerSecond | `string` | $"{rate:0.#} tok/s" | TokensPerSecond(double rate): Generation speed in the token usage readout. |
| ToolAwaitingApproval | `string` | $"{tool} is waiting for your approval" | ToolAwaitingApproval(string tool): Heading of a tool call card whose call waits for approval; the prompt under it asks the question (ApproveTool). |
| ToolCalls | `string` | "Tool calls" | Accessible name of the list of tool calls one agent step made. |
| ToolCallDeclined | `string` | "The user declined this tool call." | The result of a tool call the user declined when it asked for approval. |
| ToolCancelled | `string` | $"{tool} was cancelled" | ToolCancelled(string tool): Heading of a tool call card whose call was cancelled before the tool produced a result. |
| ToolFailed | `string` | $"{tool} failed" | ToolFailed(string tool): Heading of a tool call card that failed. |
| ToolLoopLimitReached | `string` | $"Stopped after {roundTrips} tool round trips." | ToolLoopLimitReached(int roundTrips): The error left on a reply whose tool calls went round more times than the session allows (BitAiChatSessionOptions.MaxToolRoundtrips). |
| ToolRejected | `string` | $"{tool} was declined" | ToolRejected(string tool): Heading of a tool call card whose call was declined when it asked for approval. |
| Transcript | `string` | "Conversation" | Accessible name of the transcript region. |
| UnreadableProperty | `string` | $"'{name}' could not be read as {type}" | UnreadableProperty(string name, string type): Shown for a generated property whose value could not be read as the type the component declares for it, so it was not passed. |
| Untitled | `string` | "Untitled" | Fallback title for a conversation with no title yet. |
| UploadFailed | `string` | "Upload failed" | Shown on an attachment whose upload failed without a reason. |
| UsageLine | `string` | $"{label}: {tokens:N0}" | UsageLine(string label, long tokens): One line of the usage breakdown. |
| Version | `string` | "Version" | Label for the artifact version selector. |
| VersionNumber | `string` | $"{Version} {version}" | VersionNumber(int version): Label of one entry in the artifact version selector. |
| WaitingForYou | `string` | "Waiting for your answer" | Shown when an agent is waiting for the user. |
| Yesterday | `string` | "Yesterday" | Group heading for conversations updated yesterday. |
### BitAiComponentBase Properties
The base class of every AI component: a BitComponentBase that also knows the options in force, their strings, and the renderers to use, each read from a cascading value. The options are the cascaded BitAiUiOptions (what a BitAiOptionsProvider cascades), else the ones registered with AddBitBlazorUIAIServices (ConfigureUi), else BitAiUiOptions.Default; the strings are the Strings of those options. The renderers are the cascaded BitAiRendererRegistry (a CascadingValue of one - see the Renderers of a region example of AiMessagePartView), else the one AddBitBlazorUIAIServices registers (ConfigureRenderers). A component that follows a stream re-renders through a BitAiRenderScheduler, at most once per RenderInterval of its options rather than once per token.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| CascadedOptions | `BitAiUiOptions?` | null | [CascadingParameter] The options cascaded by the nearest BitAiOptionsProvider, or by any CascadingValue of a BitAiUiOptions. While it is null, the registered options are used. |
| CascadedRenderers | `BitAiRendererRegistry?` | null | [CascadingParameter] The renderer registry cascaded to the component with a CascadingValue. While it is null, the registry registered with AddBitBlazorUIAIServices (ConfigureRenderers) is used. The registered one is app-wide - one instance for every user of a server-side app - so a page or a test with renderers of its own cascades a registry of its own rather than changing the registered one; it replaces the registered one for everything inside it. |
### BitAiRenderScheduler Properties
Coalesces change notifications that arrive far faster than a browser can paint - a fast model streams hundreds of deltas a second - into at most one render per interval, which is what RenderInterval sets for the AI components. A page that follows a stream of its own uses one the same way: new BitAiRenderScheduler(() => InvokeAsync(StateHasChanged)), Request() on every change, FlushAsync() when the stream ends, and DisposeAsync() with the page. While a render is in flight, more requests only mark it dirty, so a slow renderer falls behind in renders, never in memory.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| new(flush, interval?) | `constructor` | | flush (Func<Task>) is run when a render is due - InvokeAsync(StateHasChanged) for a component; interval (TimeSpan?) is the least time between two renders, DefaultInterval when it is null. |
| DefaultInterval | `TimeSpan` | TimeSpan.FromMilliseconds(50) | Static: one render every 50 milliseconds, twenty a second - continuous to the eye, and comfortable over a Blazor Server circuit on a poor connection. The default of BitAiUiOptions.RenderInterval. |
| Request() | `void` | | Asks for a render. Cheap and safe to call from any thread, on every token: the requests of one interval become one render. |
| FlushAsync() | `Task` | | Renders now, bypassing the interval. Call it when a stream ends, so its final state is not left waiting behind a timer. |
| RenderCount | `int` | 0 | How many renders the scheduler has run, for tests and diagnostics. |
| CoalescedCount | `int` | 0 | How many requests were folded into another render, for tests and diagnostics. |
| DisposeAsync() | `ValueTask` | | Stops the scheduler: a render still waiting for its interval is dropped, and a request after it does nothing. |
## Examples
\n**Basic**:
```razor
```
```csharp
private static readonly BitAiCitation[] citations =
[
new("c1", new BitAiCitationSource("render-modes", "Blazor render modes")
{
Kind = BitAiSourceKind.Web,
Url = "https://learn.microsoft.com/aspnet/core/blazor/components/render-modes",
SiteName = "Microsoft Learn",
}) { Number = 1 },
new("c2", new BitAiCitationSource("circuits", "SignalR circuit lifetime")
{
Kind = BitAiSourceKind.Document,
Url = "https://learn.microsoft.com/aspnet/core/blazor/fundamentals/signalr",
SiteName = "Microsoft Learn",
}) { Number = 2 },
];
private const string answer = "Interactive Server keeps component state on the server [1], and loses it with the circuit [2].";
private bool inlineCitations = true;
private BitAiUiOptions basicOptions = BitAiUiOptions.Default;
private void BuildBasicOptions() => basicOptions = BitAiUiOptions.Default with { InlineCitations = inlineCitations };
```
\n**Localized strings**:
```razor
```
```csharp
// citations is the one of the Basic example.
private static readonly BitAiUiOptions germanOptions = BitAiUiOptions.Default with { Strings = new GermanAiStrings() };
private readonly BitAiTokenUsage usage = new() { InputTokens = 12_400, OutputTokens = 1_860, CachedInputTokens = 9_800 };
private sealed class GermanAiStrings : BitAiStrings
{
private static readonly CultureInfo German = CultureInfo.GetCultureInfo("de-DE");
public override string AgentRunning => "Läuft";
public override string WaitingForYou => "Wartet auf Ihre Antwort";
public override string AgentCompleted => "Fertig";
public override string Sources => "Quellen";
public override string Context => "Kontext";
public override string Tokens => "Token";
public override string InputTokens => "Eingabe";
public override string OutputTokens => "Ausgabe";
public override string CachedTokens => "Zwischengespeichert";
public override string ContextWarning => "Das Kontextfenster füllt sich";
public override string ContextCritical => "Das Kontextfenster ist fast voll";
public override string CitationLabel(int? number, string title) => number is null ? $"Quelle: {title}" : $"Quelle {number}: {title}";
public override string ContextUsage(long used, long window) => string.Format(German, "{0:N0} / {1:N0} {2}", used, window, Tokens);
public override string UsageLine(string label, long tokens) => string.Format(German, "{0}: {1:N0}", label, tokens);
public override string FormatTokens(long tokens) => tokens < 1000
? tokens.ToString("N0", German)
: string.Format(German, "{0:0.0} Tsd.", tokens / 1000.0);
}
```
\n**Nested providers**:
```razor
```
```csharp
// answer, citations and germanOptions are the ones of the examples above.
private static readonly BitAiUiOptions innerOptions = germanOptions with { InlineCitations = false };
```
\n**Registered options**:
```razor
```
```csharp
private readonly BitAiAgentRun usageRun = CreateUsageRun();
private static BitAiAgentRun CreateUsageRun()
{
var run = new BitAiAgentRun(agentName: "Research agent") { Goal = "Summarize the release notes" };
run.SetPlan(
[
new BitAiAgentPlanStep("fetch", "Fetch the release notes"),
new BitAiAgentPlanStep("summarize", "Summarize them"),
]);
run.SetStatus(BitAiAgentRunStatus.Running);
run.Steps[0].Start();
run.AddUsage(new BitAiTokenUsage { InputTokens = 1_850, OutputTokens = 420, Cost = 0.0119m, Currency = "USD" });
return run;
}
```
`Program.cs`:
```csharp
builder.Services.AddBitBlazorUIAIServices(ai =>
{
ai.UseTransport();
// The options every AI component outside a BitAiOptionsProvider uses.
ai.ConfigureUi(options => options with
{
ShowUsage = true,
ShowModelName = true,
});
});
```
\n**Render interval**:
```razor
Start the run
@if (streamingRun is not null)
{
}
```
```csharp
private readonly BitAiUiOptions fastOptions = BitAiUiOptions.Default with { ShowUsage = true };
private readonly BitAiUiOptions slowOptions = BitAiUiOptions.Default with { ShowUsage = true, RenderInterval = TimeSpan.FromSeconds(1) };
private BitAiAgentRun? streamingRun;
private bool isStreaming;
private async Task StartStreamingRun()
{
isStreaming = true;
var run = new BitAiAgentRun(agentName: "Writer") { Goal = "Draft the announcement" };
streamingRun = run;
run.SetPlan([new BitAiAgentPlanStep("draft", "Draft it")]);
run.SetStatus(BitAiAgentRunStatus.Running);
run.Steps[0].Start();
for (var i = 0; i < 100; i++)
{
await Task.Delay(50);
run.AddUsage(new BitAiTokenUsage { OutputTokens = 7 });
}
run.Steps[0].Complete(summary: "700 tokens written");
run.SetStatus(BitAiAgentRunStatus.Completed);
isStreaming = false;
}
```
\n**Density & scheme**:
```razor
```
```csharp
// citations is the one of the Basic example.
private readonly BitTheme compactTheme = BitThemeDensityPresets.CreateCompactOverlay();
private readonly BitTheme spaciousTheme = BitThemeDensityPresets.CreateSpaciousOverlay();
```