# AiArtifactPartView
## Description
BitAiArtifactPartView is what a message shows where it introduced an artifact. The artifact belongs to the conversation rather than to the message, so the part only names it: the view looks it up in the conversation by its id and shows the shared BitAiArtifactView, opened at the version this turn produced - so a later revision never rewrites what an earlier turn appears to have said. An artifact the conversation does not hold (yet) is named by a placeholder tag rather than dropped, so the turn still says it produced one.
## Parameters
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Classes | `BitAiArtifactPartViewClassStyles?` | null | Custom CSS classes for different parts of the artifact part view. |
| Conversation | `BitAiConversation?` | null | The conversation that holds the artifact, which the view finds it in by the id of the part (BitAiConversation.FindArtifact). While it is null, or holds no artifact of that id, the part is shown as a placeholder tag. The artifact is looked up each time the view's parameters are set, so one that arrives later is shown once the parent renders the view again; the panel then follows the artifact itself as it streams and is revised. |
| Part | `BitAiArtifactPart` | | The part of the message that references the artifact (required): its ArtifactId names it and its ArtifactVersion is the version the panel opens at, the latest when it is null. |
| Styles | `BitAiArtifactPartViewClassStyles?` | null | Custom CSS styles for different parts of the artifact part view. |
| AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. |
| Disabled | `bool` | false | Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction. |
| ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name. |
| Id | `string?` | null | Gets or sets the unique identifier for the component's root element. |
| Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
## Public Members
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. |
## Enums
### BitVisibility Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
### BitDir Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
## Sub Classes
### BitAiArtifactPartViewClassStyles Properties
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Root | `string?` | null | Custom CSS classes/styles for the root element of the BitAiArtifactPartView. |
| ArtifactView | `BitAiArtifactViewClassStyles?` | null | Custom CSS classes/styles for the BitAiArtifactView the BitAiArtifactPartView shows the artifact in. |
| Placeholder | `BitTagClassStyles?` | null | Custom CSS classes/styles for the BitTag the BitAiArtifactPartView shows when the conversation does not hold the artifact. |
### BitAiArtifactPart Properties
The part of a message that says it introduced an artifact. It holds no content of its own - the artifact is the conversation's - only which artifact, and at which version. A session adds one to the message whose transport opened the artifact (a BitAiArtifactCreatedEvent). Its Kind is BitAiMessagePartKinds.Artifact ("artifact"); like every part it also has a PartId, a Version and a Changed event (see AiMessagePartView).
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| new(artifactId, partId?) | `constructor` | | Creates a reference to the artifact of that id; a null partId generates one. |
| ArtifactId | `string` | | The id of the artifact in the conversation. |
| ArtifactVersion | `int?` | null | The version of the artifact this turn introduced, which the panel opens at (the latest when it is null), so an older turn keeps showing what it produced. Settable: a session stamps it with the version the turn opened. Not to be confused with Version, which counts the changes of the part itself. |
## Examples
\n**Basic**:
```razor
```
```csharp
// A conversation holding one artifact, the way a session leaves it after a turn that wrote one.
private readonly BitAiConversation conversation = new();
private readonly BitAiArtifactPart notesPart = new("art-notes");
protected override void OnInitialized()
{
var notes = conversation.GetOrAddArtifact("art-notes", BitAiArtifactKind.Document, "Meeting notes");
notes.SetContent("""
## Meeting notes
- Ship the AI components in the next release.
- **Owner**: the UI team.
""");
notes.Complete("First draft");
}
```
\n**Versions per turn**:
```razor
@implements IAsyncDisposable
@(readmeSession.Conversation.Messages.Count == 0 ? "Write me a README" : "Tighten it and add an install step")
@foreach (var message in readmeSession.Conversation.Messages)
{
```
```csharp
// A conversation holding one artifact, the way a session leaves it after a turn that wrote one.
private readonly BitAiConversation conversation = new();
private readonly BitAiArtifactPart notesPart = new("art-notes");
protected override void OnInitialized()
{
var notes = conversation.GetOrAddArtifact("art-notes", BitAiArtifactKind.Document, "Meeting notes");
notes.SetContent("""
## Meeting notes
- Ship the AI components in the next release.
- **Owner**: the UI team.
""");
notes.Complete("First draft");
}
// An artifact the conversation does not hold.
private readonly BitAiArtifactPart missingPart = new("art-deleted");
```
\n**Cascading parameters**:
```razor
```
```csharp
// A conversation holding one artifact, the way a session leaves it after a turn that wrote one.
private readonly BitAiConversation conversation = new();
private readonly BitAiArtifactPart notesPart = new("art-notes");
protected override void OnInitialized()
{
var notes = conversation.GetOrAddArtifact("art-notes", BitAiArtifactKind.Document, "Meeting notes");
notes.SetContent("""
## Meeting notes
- Ship the AI components in the next release.
- **Owner**: the UI team.
""");
notes.Complete("First draft");
}
private readonly BitAiArtifactPart missingPart = new("art-deleted");
private readonly BitAiArtifactPartViewParams[] artifactPartViewParams =
[
new()
{
Styles = new()
{
ArtifactView = new() { Header = "background-color: var(--bit-clr-pri-light);" },
Placeholder = new() { Root = "border-style: dashed;" },
},
},
];
```
\n**Style & Class**:
```razor
```
```csharp
// A conversation holding one artifact, the way a session leaves it after a turn that wrote one.
private readonly BitAiConversation conversation = new();
private readonly BitAiArtifactPart notesPart = new("art-notes");
protected override void OnInitialized()
{
var notes = conversation.GetOrAddArtifact("art-notes", BitAiArtifactKind.Document, "Meeting notes");
notes.SetContent("""
## Meeting notes
- Ship the AI components in the next release.
- **Owner**: the UI team.
""");
notes.Complete("First draft");
}
private readonly BitAiArtifactPart missingPart = new("art-deleted");
```
\n**RTL**:
```razor
```
```csharp
private readonly BitAiConversation conversation = new();
private readonly BitAiArtifactPart persianPart = new("art-persian");
private readonly BitAiArtifactPart missingPart = new("art-deleted");
protected override void OnInitialized()
{
var persian = conversation.GetOrAddArtifact("art-persian", BitAiArtifactKind.Document, "صورت جلسه");
persian.SetContent("""
## صورت جلسه
- انتشار اجزای هوش مصنوعی در نسخه بعدی.
- **مسئول**: تیم رابط کاربری.
""");
persian.Complete();
}
```
@(message.Role.IsUser ? "You" : "Assistant"): @message.GetText()
@foreach (var part in message.PartsOf())
{
}
}
```
```csharp
// A scripted transport that drafts a README into the artifact art-readme, and revises it on the next turn (see the next tab).
private readonly BitAiChatSession readmeSession = new(AiDemoContentTransports.Artifacts());
private BitAiRenderScheduler? renderScheduler;
protected override void OnInitialized()
{
// The session says so on every streamed delta; the scheduler turns any number of those into one render per 50 ms.
renderScheduler = new(() => InvokeAsync(StateHasChanged));
readmeSession.StateChanged += renderScheduler.Request;
}
private Task SendAsync() => readmeSession.SubmitAsync(readmeSession.Conversation.Messages.Count == 0 ? "Write me a README" : "Tighten it and add an install step");
public async ValueTask DisposeAsync()
{
if (renderScheduler is not null) await renderScheduler.DisposeAsync();
await readmeSession.DisposeAsync();
}
```
`AiDemoContentTransports.cs`:
```csharp
public static IBitAiTransport Artifacts() =>
new AiScriptedTransport((request, token) => AiScript.Stream(token, async yielder =>
{
const string artifactId = "art-readme";
// Every turn after the first is a revision, numbered in the body, so no version comes out the same as the one
// before it.
var revision = request.Messages.Count(m => m.Role.IsUser) - 1;
var isRevision = revision > 0;
await yielder(new BitAiMessageStartedEvent());
var intro = revision switch
{
0 => "Here is a first draft. Tell me what to change, and I will revise it.",
1 => "Revised. I tightened the opening and added the install step.",
_ => $"Revised again, into revision {revision}.",
};
await foreach (var evt in AiScript.Write(intro, 4, 12, token)) await yielder(evt);
// The session adds a BitAiArtifactPart to this message, stamped with the version this opens.
await yielder(new BitAiArtifactCreatedEvent(artifactId, BitAiArtifactKind.Document, "Project README")
{
Language = "markdown",
});
var body = isRevision
? $"""
# Bit.BlazorUI.AI
The AI UI layer of bit BlazorUI: conversations, streaming, tools, agents, and artifacts.
## Install
```bash
dotnet add package Bit.BlazorUI.AI
```
## Why
Chat is the easy part. What takes the time is everything around it: partial JSON,
tool approval, citation anchoring, and not re-rendering the world on every token.
_Revision {revision}._
"""
: """
# Bit.BlazorUI.AI
The AI components of bit BlazorUI.
## Why
Chat is the easy part. Everything around it is what takes the time.
""";
foreach (var slice in AiScript.Slice(body, 12))
{
await AiScript.Pause(60, token);
await yielder(new BitAiArtifactDeltaEvent(artifactId, slice));
}
await yielder(new BitAiArtifactCompletedEvent(artifactId)
{
Summary = revision switch
{
0 => "First draft",
1 => "Tightened the opening, added install",
_ => $"Revision {revision}",
},
});
await yielder(new BitAiMessageCompletedEvent());
}));
```
\n**Missing artifacts**:
```razor