Skip to content

Guided tour

FabrCore 2.0 · Release and package availability

These guides track the current 2.0 source. Stable 2.0.0 publication is pending; package commands show the release target. Until it is published, follow the source quick start or use a matching available prerelease set. Release migration · Runtime modes

MODULE 02 · LESSON 2.3

Use messages, channels, and arguments intentionally

Carry routing, channel context and application metadata without mixing their roles.

Lesson 8 of 86 · FabrCore 2.0

Overview

AgentConfiguration.Args tunes an instance. AgentMessage.Args carries per-turn metadata. For Operations Desk, RequestId is a useful application argument; the signed-in principal must come from the Host. Response() retains the routing relationship, while telemetry uses explicit trace fields.

Separate lasting settings from one-turn context

AgentConfiguration.Args belongs to the instance and can configure behavior across turns. AgentMessage.Args accompanies one message. RequestId=SR-1042 is useful per-turn context for a request page; a plugin's default endpoint is an instance setting. A model can help interpret a request, but trusted code should validate the request ID and authorize access before touching the record.

Correlation is not conversation content

Channel can tell your application that a turn came from operations-desk. Routing and trace fields connect the reply and telemetry to the incoming work. These values are not instructions to include in the answer. Use message.Response() to preserve the reply relationship, and inspect Args in trusted code instead of forcing users to repeat every machine-readable value in prose.

Construct the message envelope

  1. Send RequestId=SR-1042 in AgentMessage.Args and read it defensively with TryGetValue. Give the request a meaningful application MessageType.
  2. Branch on Channel only for presentation capabilities, such as text-only A2A output versus a Surface card. Do not infer permission from that branch.
  3. Pass large structured application data through the documented Data/file contract rather than flattening secrets or entire documents into arguments.
Client request · member snippet
var request = new AgentMessage
{
    ToHandle = "assistant",
    Message = "Investigate this service request.",
    MessageType = "request.investigate",
    Channel = "operations-desk",
    Args = new() { ["RequestId"] = "SR-1042" }
};

// Inside OnMessage: metadata is not authorization.
message.Args?.TryGetValue("RequestId", out var requestId);
var response = message.Response();
Message Metadata · reference snippet
var message = new AgentMessage
{
    Message = "Process order",
    State = new() { ["priority"] = "high", ["source"] = "web-api" },
    Args = new() { ["orderId"] = "ORD-123" },
};
Message Metadata · reference snippet
public override async Task<AgentMessage> OnMessage(AgentMessage message)
{
    var response = message.Response();

    if (message.Channel == "a2a")
    {
        // A2A groups related turns by contextId, and carries any caller-supplied metadata
        // (Copilot Studio puts its conversation history there) as raw JSON.
        var contextId = message.Args?.GetValueOrDefault("A2A:ContextId");
        var callerMetadata = message.Args?.GetValueOrDefault("A2A:Metadata");
    }

    response.Message = "...";
    return response;
}

Inspect one envelope end to end

  1. Send the illustrated AgentMessage with Channel=operations-desk and Args containing RequestId=SR-1042. Inspect it at the receiving handler before invoking a model.
  2. Verify the handler can read RequestId while the visible message remains a normal user question. Change RequestId for another turn and confirm the instance's saved Args did not change.
  3. Return message.Response() and inspect the caller's received response/correlation. The reply should be associated with the request that triggered it, rather than appearing as an unrelated notification.

You have separated UI text, per-turn metadata, persistent instance settings and transport context. Each value can now be validated and diagnosed at the component that owns it.

If the result is different

Keep configuration and message arguments distinct. Addon-prefixed A2A metadata is transport context and may contain caller-controlled content.

Go deeper

Explore the related documentation.