Assets Helper
Inside a workflow code node, Assets is available as a global helper for working with stored assets.
Use it to resolve assets by name, load their content, create new assets, and delete temporary ones.
For the underlying asset model and storage concepts, see Assets.
Code Node Access
You do not need to resolve AssetHelper from dependency injection inside a code node.
SharpOMatic provides it automatically as the global Assets.
The most common pattern is:
- read an
AssetReffromContext - load bytes, text, or a stream through
Assets - create a new asset if you need to persist output
- write the resulting
AssetRefback intoContext
var inputAsset = Context.Get<AssetRef>("input.document");
var text = await Assets.LoadAssetTextAsync(inputAsset);
var updatedText = text.ToUpperInvariant();
var outputAsset = await Assets.AddAssetFromBytesAsync(
System.Text.Encoding.UTF8.GetBytes(updatedText),
"document-uppercase.txt",
"text/plain");
Context.Set("output.document", outputAsset);
Resolving Assets
GetAssetRefAsync
Use GetAssetRefAsync when you know the asset name and want an AssetRef to place into the context or pass to another helper.
var logo = await Assets.GetAssetRefAsync("branding/logo.png");
Context.Set("input.logo", logo);
Names can be:
- a run asset name
- a conversation asset name
- a library asset name
- a folder-qualified library name such as
branding/logo.png
Name-based resolution uses the current execution scope. Inside a conversation turn, the helper checks run assets first, then conversation assets, then library assets. Outside conversations, it checks run assets and then library assets.
GetAssetAsync
Use GetAssetAsync when you need metadata such as media type, size, or creation time.
var asset = await Assets.GetAssetAsync("templates/system-prompt.md");
Context.Set("output.assetName", asset.Name);
Context.Set("output.mediaType", asset.MediaType);
Context.Set("output.sizeBytes", asset.SizeBytes);
Loading Asset Content
The load methods all support the same input styles:
AssetRefGuid- asset name
Assetfor some overloads
In code nodes, AssetRef is usually the cleanest option because it flows naturally through Context.
LoadAssetBytesAsync
Use LoadAssetBytesAsync for binary assets such as images, PDFs, ZIP files, or any content you want to process as raw bytes.
var imageAsset = Context.Get<AssetRef>("input.image");
var imageBytes = await Assets.LoadAssetBytesAsync(imageAsset);
Context.Set("output.byteLength", imageBytes.Length);
This is the method you will most often use before calling helpers such as ImageHelper.
LoadAssetTextAsync
Use LoadAssetTextAsync for prompts, templates, markdown, JSON, CSV, or other text files.
var promptAsset = Context.Get<AssetRef>("input.promptTemplate");
var promptText = await Assets.LoadAssetTextAsync(promptAsset);
var userQuestion = Context.Get<string>("input.question");
Context.Set("output.finalPrompt", $"{promptText}\n\nQuestion: {userQuestion}");
If you do not specify an encoding, UTF-8 is used.
LoadAssetStreamAsync
Use LoadAssetStreamAsync when you want stream-based processing instead of loading the entire file into memory first.
var csvAsset = Context.Get<AssetRef>("input.csvFile");
await using var stream = await Assets.LoadAssetStreamAsync(csvAsset);
using var reader = new StreamReader(stream);
var firstLine = await reader.ReadLineAsync();
Context.Set("output.header", firstLine ?? string.Empty);
This is a better fit for large files or APIs that already accept Stream.
Creating Assets
All add methods return an AssetRef.
The default scope is Run, which is usually what you want for workflow-generated output.
AddAssetFromBytesAsync
Use AddAssetFromBytesAsync when you already have the final content as a byte[].
var text = Context.Get<string>("output.finalPrompt");
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
var promptAsset = await Assets.AddAssetFromBytesAsync(
bytes,
"final-prompt.txt",
"text/plain");
Context.Set("output.promptAsset", promptAsset);
AddAssetFromStreamAsync
Use AddAssetFromStreamAsync when your content already exists as a stream.
var json = """
{
"success": true,
"source": "workflow"
}
""";
await using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));
var jsonAsset = await Assets.AddAssetFromStreamAsync(
stream,
"result.json",
"application/json");
Context.Set("output.resultAsset", jsonAsset);
AddAssetFromBase64Async
Use AddAssetFromBase64Async when another node or external API returned base64 text.
var base64 = Context.Get<string>("input.base64Image");
var imageAsset = await Assets.AddAssetFromBase64Async(
base64,
"generated.png",
"image/png");
Context.Set("output.generatedImage", imageAsset);
AddAssetFromFileAsync
Use AddAssetFromFileAsync when the workflow host can access a local server file.
This reads from the machine running SharpOMatic, not from the browser.
var localAsset = await Assets.AddAssetFromFileAsync(
@"C:\imports\reference.pdf",
"reference.pdf",
"application/pdf");
Context.Set("output.referenceFile", localAsset);
AddAssetFromUriAsync
Use AddAssetFromUriAsync when you want to download content from a URL and store it as an asset.
var uri = new Uri("https://example.com/manual.pdf");
var downloaded = await Assets.AddAssetFromUriAsync(
uri,
"manual.pdf",
"application/pdf");
Context.Set("output.manual", downloaded);
Creating Library Assets
If you want the created asset to be reusable outside the current run, pass AssetScope.Library:
var bytes = System.Text.Encoding.UTF8.GetBytes("Shared prompt content");
var sharedAsset = await Assets.AddAssetFromBytesAsync(
bytes,
"shared-prompt.txt",
"text/plain",
AssetScope.Library);
Context.Set("output.sharedAsset", sharedAsset);
Creating Conversation Assets
If you are inside a conversation-enabled workflow and want the asset to remain available to later turns, pass AssetScope.Conversation:
var bytes = System.Text.Encoding.UTF8.GetBytes("Turn summary");
var conversationAsset = await Assets.AddAssetFromBytesAsync(
bytes,
"turn-summary.txt",
"text/plain",
AssetScope.Conversation);
Context.Set("output.summaryAsset", conversationAsset);
This only works when the current run belongs to a conversation.
If you call it from a standard one-shot workflow run, SharpOMatic throws because there is no active conversationId.
Deleting Assets
Use DeleteAssetAsync when you created a temporary asset and no longer want to keep it.
Like the load methods, it accepts multiple input types including AssetRef, Guid, Asset, and name.
var tempAsset = Context.Get<AssetRef>("temp.generatedFile");
await Assets.DeleteAssetAsync(tempAsset);
Context.Set("temp.generatedFile", null);
Be careful with deletion if you are working with shared library assets. If you delete by name, the same scope precedence applies: run first, then conversation, then library.
Choosing The Right Method
Use:
GetAssetRefAsyncwhen you need a reference by nameGetAssetAsyncwhen you need metadataLoadAssetBytesAsyncfor binary contentLoadAssetTextAsyncfor text contentLoadAssetStreamAsyncfor large or stream-based processingAddAssetFromBytesAsyncwhen you already have bytesAddAssetFromStreamAsyncwhen you already have a streamAddAssetFromBase64Asyncwhen another system returned base64AddAssetFromFileAsyncfor local server filesAddAssetFromUriAsyncto download and persist remote contentDeleteAssetAsyncto clean up assets you no longer need