Skip to content
Shiny.NET
Commercial SupportGuaranteed response times on Shiny bug fixes, straight from the maintainers. Plans from US$1,500 a year.See the plans

Images & Attachments

Images travel with an AiInput and are stored as attachments: the message document only holds an ImagePart with an AttachmentRef, never the bytes.

var turn = session.Send(
AiInput.Text("What plant is this?")
.WithImage(photoBytes, "image/jpeg", description: "plant", retention: ImageRetention.DropAfterTurn)
);

WithImage adds an AiImage(Data, MediaType, Description, Retention) to AiInput.Images. When the turn starts, the session saves each image through the IAiAttachmentStore and stores the user message with an ImagePart(Attachment, Description, Retention) per image. AiChatView does this for you when AllowImages is on, and the camera tool does it for photos.

ImageRetention The model sees the image… Stored
DropAfterTurn (default) in the turn it arrived in; later prompts say [image: {description}] yes
KeepInContext in every prompt until the message is compacted (costs tokens every turn) yes
DontStore once, from memory, in the turn it arrived in; then it’s gone no

Images are counted at roughly 1K tokens each in context estimates (providers vary with image size).

Store Registration Notes
InMemoryAiAttachmentStore default lost when the app exits
FileAiAttachmentStore opts.UseFileAttachments(directory) files under {directory}/{sessionId}/; provides a display URI (the file path) for chat bubbles
your own opts.SetAttachmentStore<T>() implement IAiAttachmentStore
builder.Services.AddShinyAiConversation(opts =>
{
opts.SetSqliteDocDbStores(Path.Combine(FileSystem.AppDataDirectory, "ai.db"));
opts.UseFileAttachments(Path.Combine(FileSystem.AppDataDirectory, "ai_attachments"));
});
public interface IAiAttachmentStore
{
Task<AttachmentRef> Save(ReadOnlyMemory<byte> content, string mediaType, string sessionId, CancellationToken ct = default);
Task<byte[]?> Load(string attachmentId, CancellationToken ct = default);
Task Delete(string attachmentId, CancellationToken ct = default);
Task DeleteForSession(string sessionId, CancellationToken ct = default);
string? GetDisplayUri(string attachmentId) => null; // for UIs; optional
}

IAiSessionManager.Delete(sessionId) calls DeleteForSession, so deleting a conversation removes its images. Files are not encrypted; use a custom store if conversations are sensitive.

A tool can’t put an image in front of the model on most providers, but it can queue a follow-up: tools added in OnBeforeTurn get the TurnContext, and context.QueueFollowUp(input) sends another user input once the current model round ends, as a second round of the same turn (same turn id, events and voice playback). End the round by setting FunctionInvokingChatClient.CurrentContext.Terminate = true. This is how the camera tool delivers photos.