Input Blob Artifact Saving

Purpose

Within the broader scope of the Agent Execution Runner — which orchestrates agent execution by managing message appending, agent selection, and session state updates — the subtopic Input Blob Artifact Saving addresses the need to persist binary or large data blobs included in user input messages as durable artifacts. This functionality ensures that any input blobs embedded inline in messages (such as files or binary data) are extracted and saved as separate artifacts in the session's artifact store before agent processing continues.

The existence of this feature solves several practical problems:

This subtopic adds an important persistence layer for binary inputs within the agent execution flow, complementing other session and artifact management features.

Functionality

The core workflow of Input Blob Artifact Saving happens during the pre-processing of user input messages before the main agent execution starts. This is implemented inside the Runner component of the Agent Execution Runner topic, specifically in the method responsible for appending messages to the session:

func (r *Runner) appendMessageToSession(ctx agent.InvocationContext, storedSession session.Session, msg *genai.Content, saveInputBlobsAsArtifacts bool) error {
    if msg == nil {
        return nil
    }

    artifactsService := ctx.Artifacts()
    if artifactsService != nil && saveInputBlobsAsArtifacts {
        for i, part := range msg.Parts {
            if part.InlineData == nil {
                continue
            }
            fileName := fmt.Sprintf("artifact_%s_%d", ctx.InvocationID(), i)
            if _, err := artifactsService.Save(ctx, fileName, part); err != nil {
                return fmt.Errorf("failed to save artifact %s: %w", fileName, err)
            }
            // Replace the part with a text placeholder
            msg.Parts[i] = &genai.Part{
                Text: fmt.Sprintf("Uploaded file: %s. It has been saved to the artifacts", fileName),
            }
        }
    }

    event := session.NewEvent(ctx.InvocationID())
    event.Author = "user"
    event.LLMResponse = model.LLMResponse{
        Content: msg,
    }

    if err := r.sessionService.AppendEvent(ctx, storedSession, event); err != nil {
        return fmt.Errorf("failed to append event to sessionService: %w", err)
    }
    return nil
}

Key Steps in the Workflow

  1. Detection of Inline Blobs:
    The method inspects each part of the incoming user message (msg.Parts) for the presence of InlineData (blobs).

  2. Conditional Saving:
    If the feature is enabled (saveInputBlobsAsArtifacts flag) and an artifact.Service is available, each inline blob is saved as an artifact.

  3. Artifact Naming:
    Each blob is assigned a unique artifact filename based on the current invocation ID and the part index, e.g., "artifact_<invocation_id>_<part_index>".

  4. Saving to Artifact Service:
    The blob part is persisted by calling artifactsService.Save(), which stores the data in the configured artifact backend (in-memory, GCS, etc.).

  5. Message Replacement:
    After saving the blob, the original message part containing the inline blob is replaced with a textual placeholder indicating the artifact filename and that it has been saved externally.

  6. Session Event Creation:
    A new user-authored session event is created with the modified message and appended to the session via sessionService.AppendEvent.

  7. Agent Execution Continues:
    Once the blobs are safely stored and the session updated, the agent execution proceeds with the cleaned message content.

Interaction with Other Components

Integration

The Input Blob Artifact Saving subtopic is tightly integrated with the core responsibilities of the Agent Execution Runner:

The overall flow, including this artifact saving step, fits into the agent execution lifecycle as shown below:

sequenceDiagram
participant User
participant Runner
participant ArtifactService
participant SessionService
participant Agent
User->>Runner: Send user message with inline blobs
Runner->>ArtifactService: Save each inline blob as artifact
ArtifactService-->>Runner: Artifact saved with file name
Runner->>Runner: Replace inline blob parts with placeholders
Runner->>SessionService: Append user message event with placeholders
SessionService-->>Runner: Event appended
Runner->>Agent: Run agent with cleaned message
Agent-->>Runner: Yield agent events

This sequence highlights the artifact saving step right after receiving the user message and before the agent executes.

Code Snippet Highlight

The appendMessageToSession method both detects and persists input blobs, then updates the session event with a sanitized message. This is a crucial integration point enabling the saving of input blobs as artifacts transparently:

if artifactsService != nil && saveInputBlobsAsArtifacts {
    for i, part := range msg.Parts {
        if part.InlineData == nil {
            continue
        }
        fileName := fmt.Sprintf("artifact_%s_%d", ctx.InvocationID(), i)
        if _, err := artifactsService.Save(ctx, fileName, part); err != nil {
            return fmt.Errorf("failed to save artifact %s: %w", fileName, err)
        }
        msg.Parts[i] = &genai.Part{
            Text: fmt.Sprintf("Uploaded file: %s. It has been saved to the artifacts", fileName),
        }
    }
}

This snippet encapsulates the essence of the subtopic: detecting, saving, and replacing inline blobs in the input message.


The Input Blob Artifact Saving subtopic forms a vital bridge between input message processing and artifact persistence within the agent execution flow, ensuring robust handling of binary data inputs in sessions.