Server
Server
The FabrCore server hosts your agents on an Orleans cluster. It provides REST and WebSocket APIs for client communication and background services for housekeeping.
Extension Methods
AddFabrCoreServer
Configures FabrCore server infrastructure including Orleans, services, and streaming.
var builder = WebApplication.CreateBuilder(args);
// Basic setup
builder.AddFabrCoreServer();
// With additional assemblies for custom agents
builder.AddFabrCoreServer(new FabrCoreServerOptions
{
AdditionalAssemblies = new List<Assembly>
{
typeof(MyCustomAgent).Assembly
}
});
What it configures:
- Orleans silo with clustering, persistence, and reminders
IFabrCoreRegistry(singleton) — Agent, plugin, and tool discoveryIFabrCoreChatClientService(singleton) — Chat client factoryIEmbeddings(singleton) — Embedding generation with cached clientIFileStorageService(singleton) — File storage with TTLFileCleanupBackgroundService— Automatic file cleanupAgentRegistryCleanupService— Automatic agent registry cleanup
UseFabrCoreServer
Registers FabrCore middleware, including the WebSocket endpoint for real-time agent communication.
var app = builder.Build();
app.UseFabrCoreServer();
// Or with options
app.UseFabrCoreServer(new FabrCoreServerOptions
{
AdditionalAssemblies = new List<Assembly> { typeof(MyAgent).Assembly }
});
Complete Startup Example
var builder = WebApplication.CreateBuilder(args);
builder.AddFabrCoreServer(new FabrCoreServerOptions
{
AdditionalAssemblies = new() { typeof(MyAgent).Assembly }
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseFabrCoreServer();
app.MapControllers();
await app.RunAsync();
FabrCoreRegistry
FabrCoreRegistry automatically discovers agents, plugins, and tools at startup by scanning loaded assemblies for alias attributes. No manual registration lists needed — decorate your classes and they're available.
Loading Additional Assemblies
If your agents, plugins, or tools are in separate assemblies, pass them via AdditionalAssemblies. This ensures the registry scans those assemblies at startup:
builder.AddFabrCoreServer(new FabrCoreServerOptions
{
AdditionalAssemblies = new List<Assembly>
{
typeof(MyCustomAgent).Assembly,
typeof(MyPluginLibrary).Assembly
}
});
FabrCore handles discovery for agents ([AgentAlias]), plugins ([PluginAlias]), and tools ([ToolAlias]) automatically. For application-level concerns like UI components or middleware, use ASP.NET Core's built-in AddApplicationPart() instead of building custom scanning systems.
How Discovery Works
| Attribute | Target | Description |
|---|---|---|
[AgentAlias("name")] | Class | Registers a FabrCoreAgentProxy under one or more aliases |
[PluginAlias("name")] | Class | Registers an IFabrCorePlugin for agent use |
[ToolAlias("name")] | Method | Registers a static method as a callable tool |
All attributes support AllowMultiple = true, so a single component can have multiple aliases:
[AgentAlias("assistant")]
[AgentAlias("my-assistant")]
public class AssistantAgent : FabrCoreAgentProxy
{
// Reachable via either alias
}
Registry API
| Method | Returns | Description |
|---|---|---|
GetAgentTypes() | List<RegistryEntry> | All discovered agents with their aliases |
GetPlugins() | List<RegistryEntry> | All discovered plugins with their aliases |
GetTools() | List<RegistryEntry> | All discovered tools with their aliases |
FindAgentType(alias) | Type? | Resolve an agent alias to its concrete type |
Discovery REST Endpoint
The registry is exposed via a built-in REST endpoint, allowing clients to discover available agents, plugins, and tools at runtime:
| Method | Endpoint | Description |
|---|---|---|
GET | /fabrcoreapi/Discovery | Returns all registered agents, plugins, and tools |
{
"agents": [
{ "typeName": "MyApp.AssistantAgent", "aliases": ["assistant", "my-assistant"] }
],
"plugins": [
{ "typeName": "MyApp.WeatherPlugin", "aliases": ["weather"] }
],
"tools": [
{ "typeName": "MyApp.MathTools.Add", "aliases": ["add-numbers"] }
]
}
The discovery endpoint makes it easy to verify your agents, plugins, and tools are correctly registered. Hit /fabrcoreapi/Discovery during development to confirm everything was picked up by the assembly scan — no guesswork needed.
REST API
All endpoints are prefixed with /fabrapi.
Agent API
| Method | Endpoint | Description |
|---|---|---|
POST | /fabrapi/Agent/create | Create one or more agents for a user |
GET | /fabrapi/Agent/health/{handle} | Get agent health status |
POST | /fabrapi/Agent/chat/{handle} | Send a message and receive a response |
All Agent API endpoints require the x-user header to identify the user.
POST /fabrapi/Agent/create
x-user: user123
[{
"handle": "my-agent",
"agentType": "MyAgent",
"models": "default",
"systemPrompt": "You are a helpful assistant."
}]
Diagnostics API
| Method | Endpoint | Description |
|---|---|---|
GET | /fabrapi/Diagnostics/agents | List all registered agents |
GET | /fabrapi/Diagnostics/agents/{key} | Get specific agent info |
GET | /fabrapi/Diagnostics/agents/statistics | Agent count statistics |
POST | /fabrapi/Diagnostics/agents/purge | Purge deactivated agents |
File & Embeddings API
| Method | Endpoint | Description |
|---|---|---|
POST | /fabrapi/File/upload | Upload a file (multipart/form-data) |
GET | /fabrapi/File/{fileId} | Download a file |
GET | /fabrapi/File/{fileId}/info | Get file metadata |
POST | /fabrapi/Embeddings | Generate a vector embedding for a single text |
POST | /fabrcoreapi/embeddings/batch | Generate embeddings for multiple texts in a single request (up to 2,048 items) |
Batch Embeddings
The batch endpoint accepts a list of items, each with a caller-provided id and text:
{
"items": [
{ "id": "item-1", "text": "First document to embed" },
{ "id": "item-2", "text": "Second document to embed" },
{ "id": "item-3", "text": "Third document to embed" }
]
}
{
"results": [
{ "id": "item-1", "vector": [0.0123, -0.0456, ...], "dimensions": 1536 },
{ "id": "item-2", "vector": [0.0789, -0.0321, ...], "dimensions": 1536 },
{ "id": "item-3", "vector": [0.0654, -0.0987, ...], "dimensions": 1536 }
]
}
Validation Rules
| Condition | Error (400) |
|---|---|
| Items is null or empty | "Items list must not be empty." |
| Any item has empty id | "Item at index {i} has an empty Id." |
| Any item has empty text | "Item at index {i} (Id='{id}') has empty Text." |
| More than 2,048 items | "Batch size {n} exceeds maximum of 2048." |
All endpoints return consistent error responses: 200 (Success), 400 (Bad Request), 404 (Not Found), 500 (Internal Server Error).
WebSocket API
Real-time communication with agents via WebSocket at the /ws endpoint.
// Browser
const ws = new WebSocket('wss://your-server/ws?userid=user123');
// Send a message
ws.send(JSON.stringify({
toHandle: "my-agent",
fromHandle: "user123",
message: "Hello, agent!"
}));
Authentication requires either the x-fabr-userid header or the userid query parameter.
Orleans Streaming
FabrCore uses Orleans streams for agent communication:
| Stream | Namespace | Purpose |
|---|---|---|
| AgentChat | AgentChat | Request/response messaging |
| AgentEvent | AgentEvent | Fire-and-forget events |
Background Services
| Service | Interval | Description |
|---|---|---|
FileCleanupBackgroundService | Configurable | Removes expired files and orphaned entries |
AgentRegistryCleanupService | Every 6 hours | Purges agents deactivated more than 7 days ago |