A master orchestration server for coordinating multiple LumiaBot instances, enabling coordinated responses, bantering systems, and cross-guild bot management.
- Bot Coordination: Orchestrate response timing between all connected LumiaBot "nodes"
- Response Ordering: Set up response order and feed necessary context across all bots
- Bantering System: Create interactive "bantering" between multiple bots
- Safety Caps: Hard cap response turns to prevent runaway bot responses
- Cross-Guild Detection: Detect when mentioned bots don't share a guild and allow independent responses
- Shared Knowledge Layer: Load markdown/frontmatter docs directly into the orchestrator for collective lookups
- Vector Retrieval: Optional LanceDB-backed semantic search with HNSW-PQ indexing and OpenAI-compatible embeddings
- Real-time Communication: WebSocket-based communication for low-latency coordination
- REST API: HTTP endpoints for management and monitoring
┌─────────────────────────────────────────────────────────────┐
│ Lumia Orchestrator │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ REST API │ │ WebSocket │ │ Services │ │
│ │ Routes │ │ Manager │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Response Coordinator │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │
│ │ │ Turn Manager │ │ Banter System│ │ Safety │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Bot Registry │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │
│ │ │ Bot Nodes │ │ Guilds │ │ Health │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ WebSocket / REST
▼
┌─────────────────────────────────────────────────────────────┐
│ LumiaBot Instances │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ LumiaBot │ │ LumiaBot │ │ LumiaBot │ │
│ │ Node 1 │ │ Node 2 │ │ Node N │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
# Clone the repository
git clone <repository-url>
cd lumia-orchestrator
# Install dependencies
bun install
# Copy environment file
cp .env.example .env
# Edit .env with your configurationCreate a .env file with the following variables:
# Server Configuration
PORT=3000
HOST=0.0.0.0
NODE_ENV=production
# Security
API_KEY=your-super-secret-api-key-min-16-chars
COUNCIL_FAMILY_NAME=Lumias
JWT_SECRET=your-jwt-secret
# Orchestrator Knowledge Graph
KNOWLEDGE_GRAPH_ENABLED=true
KNOWLEDGE_GRAPH_DIR=./knowledge_documents
KNOWLEDGE_GRAPH_TOP_K=8
KNOWLEDGE_ONLY_INCLUDE_OVER=0.2
# Optional LanceDB vector search
KNOWLEDGE_VECTOR_ENABLED=false
KNOWLEDGE_VECTOR_DB_DIR=./data/lancedb
KNOWLEDGE_VECTOR_EMBEDDING_BASE_URL=https://api.openai.com/v1
KNOWLEDGE_VECTOR_EMBEDDING_API_KEY=your-embedding-api-key
KNOWLEDGE_VECTOR_EMBEDDING_MODEL=text-embedding-3-large
KNOWLEDGE_VECTOR_EMBEDDING_BATCH_SIZE=20
# Bot Coordination Settings
MAX_RESPONSE_TURNS=5
RESPONSE_TIMEOUT_MS=30000
BANTER_COOLDOWN_MS=5000
# WebSocket Settings
WS_HEARTBEAT_INTERVAL_MS=30000
WS_MAX_CONNECTIONS=100
# Logging
LOG_LEVEL=info
LOG_FORMAT=json
# Feature Flags
ENABLE_BANTER_SYSTEM=true
ENABLE_RESPONSE_CAP=true
ENABLE_CROSS_GUILD_DETECTION=true# Development mode with hot reload
bun run dev
# Production mode
bun run startThe orchestrator can load its own shared markdown knowledge corpus from KNOWLEDGE_GRAPH_DIR.
These files use the same frontmatter format as the bot-side knowledge_documents/ folder.
Example:
---
topic: frontmatter
title: Shared Frontmatter Notes
keywords: frontmatter, metadata, markdown
type: document
priority: 8
---
Shared orchestrator knowledge goes here.This is useful when you want one central source of truth for KNOWLEDGE_GRAPH_SOURCE_MODE=1 or a second shared layer for KNOWLEDGE_GRAPH_SOURCE_MODE=2.
If you have Zensical or MkDocs-style docs, place them in knowledge_documents/to_convert/ and run:
bun run convert-knowledge-docsThis writes converted frontmatter docs into knowledge_documents/converted/.
The converter uses the document title plus its parent category path to generate frontmatter metadata and normalizes common MkDocs constructs like admonitions and tab blocks.
By default it wipes the output directory first so stale converted docs do not linger. Pass --no-clean if you want to preserve existing output.
Files inside knowledge_documents/to_convert/ are ignored by the orchestrator loader, so only the converted output is embedded and indexed at startup.
If KNOWLEDGE_VECTOR_ENABLED=true, the orchestrator will also:
- chunk each document for retrieval,
- prepend title/topic/keywords into each chunk for stronger semantic relevance,
- embed chunks through your configured OpenAI-compatible endpoint,
- store them in LanceDB,
- build an HNSW-PQ vector index plus a full-text index,
- run hybrid retrieval for better QA-style lookups.
Scoring notes:
- LanceDB vector search is distance-based, so lower cosine distance is better.
- LanceDB FTS search is BM25-based, so higher relevance is better.
- The orchestrator normalizes those signals into a shared 0-1 relevance score, blends them with metadata weighting, and filters out low-confidence hits using
KNOWLEDGE_ONLY_INCLUDE_OVER.
GET /api/v1/bots- List all registered botsGET /api/v1/bots/:botId- Get bot details
GET /api/v1/guilds- List all guildsGET /api/v1/guilds/:guildId/bots- List bots in a guild
POST /api/v1/mention- Submit a mention event for coordination
GET /api/v1/turns/:turnId- Get turn detailsPOST /api/v1/turns/:turnId/complete- Mark turn as complete
GET /api/v1/sessions- List active banter sessionsPOST /api/v1/sessions/:sessionId/end- End a session
GET /health- Health check endpointGET /api/v1/stats- Server statistics
{
"type": "register",
"payload": {
"botId": "bot-123",
"name": "LumiaBot-Alpha",
"token": "discord-token",
"guilds": ["guild-1", "guild-2"],
"metadata": {}
}
}{
"type": "heartbeat",
"payload": {
"botId": "bot-123",
"timestamp": "2024-01-01T00:00:00Z",
"guilds": ["guild-1", "guild-2"],
"status": "online"
}
}{
"type": "mention",
"payload": {
"eventId": "event-123",
"messageId": "msg-456",
"channelId": "channel-789",
"guildId": "guild-abc",
"authorId": "user-xyz",
"authorName": "UserName",
"content": "@LumiaBot-Alpha @LumiaBot-Beta hello!",
"mentionedBotIds": ["bot-123", "bot-456"],
"timestamp": "2024-01-01T00:00:00Z"
}
}{
"type": "response_complete",
"payload": {
"turnId": "turn-123",
"botId": "bot-123",
"responseContent": "Hello there! How can I help?"
}
}{
"type": "register_ack",
"payload": {
"success": true,
"botId": "bot-123",
"registeredAt": "2024-01-01T00:00:00Z"
}
}{
"type": "response_request",
"payload": {
"turnId": "turn-123",
"eventId": "event-456",
"botId": "bot-123",
"context": {
"previousMessages": [...],
"conversationId": "conv-789",
"turnCount": 0,
"maxTurns": 5,
"isBanter": false
},
"timeoutAt": "2024-01-01T00:00:30Z"
}
}{
"type": "banter_invite",
"payload": {
"sessionId": "session-123",
"inviterBotId": "bot-456",
"inviteeBotIds": ["bot-123"],
"channelId": "channel-789",
"guildId": "guild-abc",
"topic": "general chat"
}
}{
"type": "error",
"payload": {
"code": "TURN_NOT_FOUND",
"message": "Turn not found",
"details": {}
}
}To integrate the orchestrator with your LumiaBot instances:
import { LumiaBotIntegration } from 'lumia-orchestrator';
const orchestrator = new LumiaBotIntegration({
orchestratorUrl: 'ws://localhost:3000',
apiKey: 'your-api-key',
botId: 'my-bot-id',
botName: 'MyLumiaBot',
token: 'discord-bot-token',
guilds: ['guild-id-1', 'guild-id-2'],
});
// Set up response handler
orchestrator.setResponseHandler(async (context) => {
// Your bot's response logic here
// Access context.previousMessages for conversation history
return "Hello! I'm responding in turn.";
});
// Connect to orchestrator
await orchestrator.connect();
// When your bot receives a mention, notify the orchestrator
await orchestrator.notifyMention({
eventId: 'unique-event-id',
messageId: 'discord-message-id',
channelId: 'channel-id',
guildId: 'guild-id',
authorId: 'user-id',
authorName: 'UserName',
content: 'Message content with @mentions',
mentionedBotIds: ['bot-id-1', 'bot-id-2'],
timestamp: new Date(),
});
// Update guilds when bot joins/leaves guilds
orchestrator.updateGuilds(['new-guild-id-1', 'new-guild-id-2']);
// Disconnect when shutting down
orchestrator.disconnect();MIT