Progress Notifications in FabrCore

Eric Brasher February 21, 2026 at 10:07 AM 4 min read

Long-running agent operations need progress feedback. FabrCore's SendMessage with MessageKind.OneWay is the primitive for this — no dedicated streaming API required.

The Pattern

When an agent performs a long-running task, it can send progress updates back to the caller using fire-and-forget messages. The caller's handle is available via message.FromHandle:

WorkerAgent.cs
public override async Task<AgentMessage> OnMessage(
    AgentMessage message)
{
    var callerHandle = message.FromHandle;
    var items = GetWorkItems(message);

    for (int i = 0; i < items.Count; i++)
    {
        // Send progress notification
        await AgentHost.SendMessage(callerHandle,
            new AgentMessage
            {
                Message = $"Processing {i + 1}/{items.Count}",
                Kind = MessageKind.OneWay,
                Channel = "progress",
                MessageType = "status-update"
            });

        await ProcessItem(items[i]);
    }

    return new AgentMessage
    {
        Message = $"Completed {items.Count} items"
    };
}

Handling Progress on the Caller Side

The calling agent receives progress messages through its own OnMessage. Route them using the channel and message type metadata:

OrchestratorAgent.cs
public override async Task<AgentMessage> OnMessage(
    AgentMessage message)
{
    if (message.Channel == "progress"
        && message.Kind == MessageKind.OneWay)
    {
        // Forward to UI or log it
        logger.LogInformation(
            "Progress from {Agent}: {Status}",
            message.FromHandle, message.Message);
        return new AgentMessage();
    }

    // Normal message handling
    return await base.OnMessage(message);
}

Forwarding to the Client

If your UI needs to display progress, the client SDK's event system bridges the gap. Use SendEvent to push progress to connected clients:

Forwarding to Client
// In the orchestrator agent's progress handler
await AgentHost.SendEvent(new AgentEvent
{
    EventType = "progress",
    Data = message.Message
});

The client SDK receives events through the OnEvent callback, which you can wire up to your Blazor component, React state, or any other UI framework.

Why Not a Streaming API?

Teams sometimes request a dedicated streaming or progress API. Here's why the messaging primitive is sufficient:

OneWay messages are already fire-and-forget. They don't block the sender or require the receiver to respond. That's exactly the semantics you need for progress notifications.

Events bridge to the client. The SendEvent mechanism already pushes real-time data to connected clients over WebSocket. Adding a separate streaming channel would be redundant.

You control the granularity. Some operations need per-item updates, others need percentage-based progress, others need milestone notifications. A generic streaming API would either be too rigid or too abstract. With SendMessage, you send exactly the updates your use case needs.

Learn More

Check out the progress notification documentation for the complete reference.


Eric Brasher

Builder of FabrCore and OpenCaddis.