Home / Docs / WebSocket v2

WebSocket v2

Authenticated real-time agent connectivity

WebSocket v2 is FabrCore's live principal transport. It carries typed agent operations and durable agent-to-principal deliveries, while HTTP remains responsible for provisioning agents and applying blueprints.

v2 replaces the legacy wire contract.

Raw AgentMessage frames, query/header principal selection, MessageType: "command", and createagent are removed. Migrate to FabrCore.Client.WebSocket or implement the v2 ticket, handshake, envelope, delivery, and acknowledgement protocol.

Install the typed client

dotnet add package FabrCore.Client.WebSocket --version 1.7.1

Connection flow

  1. Authenticate the client's HttpClient through the application's ASP.NET Core authentication.
  2. POST /fabrcoreapi/ws/ticket. The Host resolves the authenticated principal and returns a single-use ticket valid for 30 seconds by default.
  3. Open /ws offering fabrcore.v2 and fabrcore.ticket.<token> as subprotocols.
  4. Send hello first with a stable clientId and the last persisted checkpoint.
  5. Process ordered delivery frames and acknowledge committed sequence numbers.
Identity is server-owned.

The Host overwrites sender/source fields with the authenticated principal. Bare agent targets are scoped to that principal; qualified targets pass through normal ACL enforcement. The System principal cannot connect.

Typed .NET client

Use a stable client id for the same logical browser profile, service instance, or device. Replace the in-memory checkpoint store when checkpoints must survive application restarts.

Connect, receive, and acknowledge
using FabrCore.Client.WebSocket;

var client = new FabrCoreWebSocketClient(
    authenticatedHttpClient,
    new FabrCoreWebSocketClientOptions
    {
        HostUri = new Uri("https://agents.example.com"),
        ClientId = "ops-console-browser-42"
    },
    checkpointStore);

client.ResyncRequired += (_, gap) =>
{
    // Rebuild application state through HTTP queries.
};

await client.ConnectAsync(cancellationToken);

await foreach (var delivery in client.ReadDeliveriesAsync(cancellationToken))
{
    await ApplyToLocalState(delivery.Message, cancellationToken);
    await client.AcknowledgeAsync(delivery.Sequence, cancellationToken);
}

Send a request/response message

var response = await client.SendMessageAndReceiveAsync(
    new AgentMessage
    {
        ToHandle = "assistant",
        Message = "Summarize today's incidents."
    },
    cancellationToken);

Supported operations

OperationTyped methodPurpose
message.sendSendMessageAsync / SendMessageAndReceiveAsyncExplicit asynchronous or request/response message delivery.
event.sendSendEventAsyncPublish an event.
agent.resetResetAgentAsyncSoft-reset an existing agent.
agent.health.getGetAgentHealthAsyncRead agent health at the requested detail level.
agents.tracked.listGetTrackedAgentsAsyncList agents tracked for the connected principal.
agent.tracked.checkIsAgentTrackedAsyncCheck one tracked handle.
agents.shared.listGetSharedAgentsAsyncList ACL-visible shared agents.

Creation, reconfiguration, hard eviction, blueprint application, and arbitrary provisioning are deliberately excluded. Use the Host REST APIs for those lifecycle operations.

Durable delivery, replay, and gaps

  • Agent-to-principal messages are persisted before the v2 client is notified.
  • Delivery is ordered and at-least-once for each stable clientId.
  • A reconnect resumes after the lower of the server acknowledgement and client checkpoint. Duplicates are possible; silent skips are not.
  • A new client id starts at the current tail rather than replaying another client's backlog.
  • If retention removed a required record, the server emits gap; rebuild application state through HTTP before continuing.
  • Queue saturation closes the socket with status 1013 instead of silently dropping durable deliveries.
  • Mutating client requests are not automatically retried after an indeterminate disconnect.

Host configuration

{
  "FabrCore": {
    "Host": {
      "AllowedWebSocketOrigins": ["https://app.example.com"]
    },
    "WebSocket": {
      "TicketLifetime": "00:00:30",
      "MaxConcurrentRequests": 8,
      "RequestTimeout": "00:05:00",
      "DeliveryRetention": "1.00:00:00",
      "MaxDeliveriesPerPrincipal": 10000,
      "MaxClientsPerPrincipal": 16,
      "InactiveClientExpiration": "1.00:00:00",
      "AllowDevelopmentPrincipalSelection": false
    }
  }
}

Production browser origins must be explicitly allowed. Headless clients may omit the Origin header. Keep development principal selection disabled outside local development.

v1 migration checklist

  1. Provision agents through HTTP or blueprints before connecting.
  2. Replace raw WebSocket construction with the typed client or the documented v2 handshake.
  3. Remove x-fabrcore-userhandle, userhandle, and query-string identity selection.
  4. Choose asynchronous versus request/response behavior explicitly.
  5. Persist checkpoints and make delivery handling idempotent.
  6. Implement HTTP resynchronization for ResyncRequired.
Documentation