@@ -428,7 +428,7 @@ public sealed class TextContentBlock : ContentBlock
428428public sealed class ImageContentBlock : ContentBlock
429429{
430430 private ReadOnlyMemory < byte > ? _decodedData ;
431- private ReadOnlyMemory < byte > _data ;
431+ private ReadOnlyMemory < byte > ? _data ;
432432
433433 /// <summary>
434434 /// Creates an <see cref="ImageContentBlock"/> from decoded image bytes.
@@ -437,22 +437,27 @@ public sealed class ImageContentBlock : ContentBlock
437437 /// <param name="mimeType">The MIME type of the image.</param>
438438 /// <returns>A new <see cref="ImageContentBlock"/> instance.</returns>
439439 /// <remarks>
440- /// This method stores the provided bytes as <see cref="DecodedData"/> and encodes them to base64 UTF-8 bytes for <see cref="Data"/>.
440+ /// This method stores the provided bytes as <see cref="DecodedData"/> and lazily encodes them to base64 UTF-8 bytes for <see cref="Data"/>.
441441 /// </remarks>
442442 /// <exception cref="ArgumentNullException"><paramref name="mimeType"/> is <see langword="null"/>.</exception>
443443 /// <exception cref="ArgumentException"><paramref name="mimeType"/> is empty or composed entirely of whitespace.</exception>
444444 public static ImageContentBlock FromBytes ( ReadOnlyMemory < byte > bytes , string mimeType )
445445 {
446446 Throw . IfNullOrWhiteSpace ( mimeType ) ;
447447
448- ReadOnlyMemory < byte > data = EncodingUtilities . EncodeToBase64Utf8 ( bytes ) ;
449-
450- return new ( )
451- {
452- _decodedData = bytes ,
453- Data = data ,
454- MimeType = mimeType
455- } ;
448+ return new ( bytes , mimeType ) ;
449+ }
450+
451+ /// <summary>Initializes a new instance of the <see cref="ImageContentBlock"/> class.</summary>
452+ public ImageContentBlock ( )
453+ {
454+ }
455+
456+ [ SetsRequiredMembers ]
457+ private ImageContentBlock ( ReadOnlyMemory < byte > decodedData , string mimeType )
458+ {
459+ _decodedData = decodedData ;
460+ MimeType = mimeType ;
456461 }
457462
458463 /// <inheritdoc/>
@@ -467,7 +472,16 @@ public static ImageContentBlock FromBytes(ReadOnlyMemory<byte> bytes, string mim
467472 [ JsonPropertyName ( "data" ) ]
468473 public required ReadOnlyMemory < byte > Data
469474 {
470- get => _data ;
475+ get
476+ {
477+ if ( _data is null )
478+ {
479+ Debug . Assert ( _decodedData is not null ) ;
480+ _data = EncodingUtilities . EncodeToBase64Utf8 ( _decodedData ! . Value ) ;
481+ }
482+
483+ return _data . Value ;
484+ }
471485 set
472486 {
473487 _data = value ;
@@ -508,15 +522,22 @@ public ReadOnlyMemory<byte> DecodedData
508522 public required string MimeType { get ; set ; }
509523
510524 [ DebuggerBrowsable ( DebuggerBrowsableState . Never ) ]
511- private string DebuggerDisplay => $ "MimeType = { MimeType } , Length = { DebuggerDisplayHelper . GetBase64LengthDisplay ( Data ) } ";
525+ private string DebuggerDisplay
526+ {
527+ get
528+ {
529+ string lengthDisplay = _decodedData is not null ? $ "{ _decodedData . Value . Length } bytes" : DebuggerDisplayHelper . GetBase64LengthDisplay ( Data ) ;
530+ return $ "MimeType = { MimeType } , Length = { lengthDisplay } ";
531+ }
532+ }
512533}
513534
514535/// <summary>Represents audio provided to or from an LLM.</summary>
515536[ DebuggerDisplay ( "{DebuggerDisplay,nq}" ) ]
516537public sealed class AudioContentBlock : ContentBlock
517538{
518539 private ReadOnlyMemory < byte > ? _decodedData ;
519- private ReadOnlyMemory < byte > _data ;
540+ private ReadOnlyMemory < byte > ? _data ;
520541
521542 /// <summary>
522543 /// Creates an <see cref="AudioContentBlock"/> from decoded audio bytes.
@@ -525,22 +546,27 @@ public sealed class AudioContentBlock : ContentBlock
525546 /// <param name="mimeType">The MIME type of the audio.</param>
526547 /// <returns>A new <see cref="AudioContentBlock"/> instance.</returns>
527548 /// <remarks>
528- /// This method stores the provided bytes as <see cref="DecodedData"/> and encodes them to base64 UTF-8 bytes for <see cref="Data"/>.
549+ /// This method stores the provided bytes as <see cref="DecodedData"/> and lazily encodes them to base64 UTF-8 bytes for <see cref="Data"/>.
529550 /// </remarks>
530551 /// <exception cref="ArgumentNullException"><paramref name="mimeType"/> is <see langword="null"/>.</exception>
531552 /// <exception cref="ArgumentException"><paramref name="mimeType"/> is empty or composed entirely of whitespace.</exception>
532553 public static AudioContentBlock FromBytes ( ReadOnlyMemory < byte > bytes , string mimeType )
533554 {
534555 Throw . IfNullOrWhiteSpace ( mimeType ) ;
535556
536- ReadOnlyMemory < byte > data = EncodingUtilities . EncodeToBase64Utf8 ( bytes ) ;
537-
538- return new ( )
539- {
540- _decodedData = bytes ,
541- Data = data ,
542- MimeType = mimeType
543- } ;
557+ return new ( bytes , mimeType ) ;
558+ }
559+
560+ /// <summary>Initializes a new instance of the <see cref="AudioContentBlock"/> class.</summary>
561+ public AudioContentBlock ( )
562+ {
563+ }
564+
565+ [ SetsRequiredMembers ]
566+ private AudioContentBlock ( ReadOnlyMemory < byte > decodedData , string mimeType )
567+ {
568+ _decodedData = decodedData ;
569+ MimeType = mimeType ;
544570 }
545571
546572 /// <inheritdoc/>
@@ -555,7 +581,16 @@ public static AudioContentBlock FromBytes(ReadOnlyMemory<byte> bytes, string mim
555581 [ JsonPropertyName ( "data" ) ]
556582 public required ReadOnlyMemory < byte > Data
557583 {
558- get => _data ;
584+ get
585+ {
586+ if ( _data is null )
587+ {
588+ Debug . Assert ( _decodedData is not null ) ;
589+ _data = EncodingUtilities . EncodeToBase64Utf8 ( _decodedData ! . Value ) ;
590+ }
591+
592+ return _data . Value ;
593+ }
559594 set
560595 {
561596 _data = value ;
@@ -596,7 +631,14 @@ public ReadOnlyMemory<byte> DecodedData
596631 public required string MimeType { get ; set ; }
597632
598633 [ DebuggerBrowsable ( DebuggerBrowsableState . Never ) ]
599- private string DebuggerDisplay => $ "MimeType = { MimeType } , Length = { DebuggerDisplayHelper . GetBase64LengthDisplay ( Data ) } ";
634+ private string DebuggerDisplay
635+ {
636+ get
637+ {
638+ string lengthDisplay = _decodedData is not null ? $ "{ _decodedData . Value . Length } bytes" : DebuggerDisplayHelper . GetBase64LengthDisplay ( Data ) ;
639+ return $ "MimeType = { MimeType } , Length = { lengthDisplay } ";
640+ }
641+ }
600642}
601643
602644/// <summary>Represents the contents of a resource, embedded into a prompt or tool call result.</summary>
0 commit comments