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 01 · LESSON 1.3

Write and call your first agent

Implement an echo agent and send its first request.

Lesson 3 of 86 · FabrCore 2.0

Overview

An echo turn isolates transport and provisioning from model configuration. FabrCoreAgentProxy already owns routing, status and lifecycle integration. Use message.Response() so the reply carries the correct recipient and correlation rather than constructing a disconnected message.

Creation and messaging are separate operations

Discovery answers “which implementations are installed?” Creating assistant answers “which instance belongs to dev?” The creation endpoint accepts a batch, so an HTTP success can still contain a failed item. Inspect the result before sending chat. Otherwise a later missing-agent error hides the earlier provisioning failure.

Why the response helper matters

OnMessage receives an AgentMessage envelope, not just a string. message.Response() constructs a reply tied to that incoming message's routing and correlation. Assigning response.Message changes the content without losing that relationship. Echoing the incoming text is a controlled baseline: no model, plugin, business record, or network service can alter the answer.

A model lookup log during the echo exercise

The current 2.0 runtime can inspect the default model configuration while initializing context and run-safety policy, even before the deterministic echo handler runs. Without a model catalog, this can log “Model configuration default was not found.” In the verified echo exercise, creation still succeeded and the response contained the exact input.

Use failureCount and the returned message to judge this particular echo check. A missing default alias must be resolved before the AI exercise in lesson 1.4, but this log by itself does not mean the echo handler made an inference call or that the transport failed.

Implement and call the echo agent

Download the Operations Desk source. The README lists project setup, package prerequisites and local ports.

  1. Add EchoAgent.cs to OperationsDesk.Agents and rebuild/restart the Host. Keep the Host at http://localhost:5098.
  2. Create the caller with dotnet new console -n OperationsDesk.Console -f net10.0 and replace its Program.cs with the client example below. The raw HTTP caller needs no SDK package.
  3. Run dotnet run --project OperationsDesk.Console. The x-user-handle header is only for this trusted localhost exercise; deployed clients require authenticated principal mapping.
OperationsDesk.Agents/EchoAgent.cs
using FabrCore.Core;
using FabrCore.Sdk;

[AgentAlias("ops-echo")]
public sealed class EchoAgent(
    AgentConfiguration config,
    IServiceProvider services,
    IFabrCoreAgentHost host) : FabrCoreAgentProxy(config, services, host)
{
    public override Task OnInitialize() => Task.CompletedTask;

    public override Task<AgentMessage> OnMessage(AgentMessage message)
    {
        var response = message.Response();
        response.Message = message.Message;
        return Task.FromResult(response);
    }
}
OperationsDesk.Console/Program.cs · downloadable checkpoint
using System.Net.Http.Json;
using System.Text.Json;
// Trusted localhost exercise only. External callers require authenticated principal mapping.
using var http = new HttpClient { BaseAddress = new Uri("http://localhost:5098") };
http.DefaultRequestHeaders.Add("x-user-handle", "dev");
var useTools = args.Contains("--tools");
var useAi = args.Contains("--ai") || useTools;
var alias = useAi ? "ops-assistant" : "ops-echo";
var handle = useTools ? "tool-assistant" : useAi ? "ai-assistant" : "assistant";
var prompt = args.FirstOrDefault(value => !value.StartsWith("--", StringComparison.Ordinal))
    ?? "Investigate request SR-1042";
using var created = await http.PostAsJsonAsync("/fabrcoreapi/agent/create", new[] {
    new { Handle = handle, AgentType = alias, Models = useAi ? "default" : null,
        Plugins = useTools ? new[] { "requests" } : Array.Empty<string>() }
});
created.EnsureSuccessStatusCode();
var creation = await created.Content.ReadAsStringAsync();
Console.WriteLine(creation);
using (var document = JsonDocument.Parse(creation))
{
    var failures = document.RootElement.EnumerateObject().FirstOrDefault(p =>
        p.Name.Equals("failureCount", StringComparison.OrdinalIgnoreCase));
    if (failures.Value.ValueKind == JsonValueKind.Number && failures.Value.GetInt32() != 0)
        throw new InvalidOperationException("Agent creation failed; inspect the result above.");
}
using var reply = await http.PostAsJsonAsync("/fabrcoreapi/agent/chat/" + handle, prompt);
reply.EnsureSuccessStatusCode();
Console.WriteLine(await reply.Content.ReadAsStringAsync());

Compare the sent and received text

  1. Rebuild and restart the Host after adding EchoAgent.cs. Request discovery again and find ops-echo. If it is missing, verify the project reference and deployed assembly before running the client.
  2. Run the console example against port 5098. Its first output is the creation result; inspect failureCount and any item errors. Its second output is the chat response, whose message content should contain “Investigate request SR-1042” unchanged.
  3. Run dotnet run --project OperationsDesk.Console -- "Echo check 2". The response message should now be exactly Echo check 2, showing that you called the handler with a second input. The abbreviated responses below show the fields to inspect; the actual envelope contains additional metadata.
Creation result · relevant fields from the echo check
{
  "totalRequested": 1,
  "successCount": 1,
  "failureCount": 0
}
Chat response · relevant fields from the echo check
{
  "toHandle": "dev",
  "fromHandle": "dev:assistant",
  "message": "Investigate request SR-1042"
}

This proves the client, principal selection, instance creation, routing and reply path. Keep ops-echo installed as a diagnostic even after the AI agent is added.

If the result is different

Connection refused means the Host is not reachable at that address. A missing ops-echo alias means its assembly was not discovered. A creation item error means no valid instance was provisioned. If the response is for the wrong user, check the trusted principal mapping and full handle before investigating the agent code.

Go deeper

Explore the related documentation.