@kb-labs/core-runtime
v2.94.0
Published
DI Container + Core Features Implementations for KB Labs Platform
Maintainers
Readme
@kb-labs/core-runtime
DI Container + Core Features Implementations for KB Labs Platform.
Purpose
- PlatformContainer - single DI container for all services
- initPlatform() - load adapters from kb.config.json
- Core Implementations - WorkflowEngine, JobScheduler, CronManager, ResourceManager
Dependencies
@kb-labs/core-platform -> @kb-labs/core-runtime -> plugins
(interfaces) (DI + implementations)Structure
src/
├── container.ts # PlatformContainer class
├── loader.ts # initPlatform() function
├── config.ts # PlatformConfig types
└── index.ts # Main entry pointUsage
Platform Initialization
import { initPlatform } from '@kb-labs/core-runtime';
await initPlatform({
adapters: {
analytics: '@kb-labs/analytics-adapter',
vectorStore: '@kb-labs/mind-qdrant',
llm: '@kb-labs/shared-openai',
},
core: {
resources: { defaultQuotas: { ... } },
jobs: { maxConcurrent: 10 },
},
});Accessing Services
import { platform } from '@kb-labs/core-runtime';
// Adapters (replaceable)
platform.analytics.track('event');
platform.vectorStore.search([...]);
// Core features (built-in)
platform.workflows.execute('my-workflow', input);
platform.jobs.submit({ type: 'task', payload: {...} });Configuration via kb.config.json
{
"platform": {
"adapters": {
"analytics": "@kb-labs/analytics-adapter",
"vectorStore": "@kb-labs/mind-qdrant",
"llm": "@kb-labs/shared-openai",
"embeddings": "@kb-labs/shared-openai",
"cache": "@kb-labs/core-redis",
"storage": "@kb-labs/core-fs",
"logger": "@kb-labs/core-pino",
"eventBus": null
},
"core": {
"resources": {
"defaultQuotas": {
"maxConcurrentWorkflows": 5,
"maxConcurrentJobs": 10
}
}
}
}
}For development/testing - set adapters to null to use NoOp implementations:
{
"platform": {
"adapters": {
"analytics": null,
"vectorStore": null,
"llm": null
}
}
}Adapters vs Core Features
| Aspect | Adapters | Core Features | |--------|----------|---------------| | Replaceability | Full (via config) | Built-in | | Implementation | External packages | In core-runtime | | Examples | analytics, llm | workflows, jobs |
Graceful Degradation
All platform services have NoOp fallback implementations that activate automatically when adapters aren't configured. This enables:
✅ Development without Configuration
// No kb.config.json? No problem! Platform initializes with NoOp adapters
await initPlatform();
// These calls work but do nothing (safe no-ops)
platform.analytics.track('event'); // NoOpAnalytics - silent
platform.vectorStore.search([...]); // MemoryVectorStore - empty results
platform.llm.complete('prompt'); // MockLLM - returns placeholder✅ Testing without External Dependencies
// Test without Qdrant, OpenAI, Redis, etc.
const result = await myFunction(platform.vectorStore);
// Uses MemoryVectorStore automatically✅ Partial Configuration
await initPlatform({
adapters: {
llm: '@kb-labs/shared-openai', // Real OpenAI
vectorStore: null, // MemoryVectorStore fallback
analytics: null, // NoOpAnalytics fallback
},
});
// Only LLM calls hit real API, rest are no-op
await platform.llm.complete('prompt'); // → OpenAI API call
await platform.analytics.track('event'); // → silent no-opNoOp Behavior by Service
| Service | NoOp Behavior | Production Adapter |
|---------|---------------|-------------------|
| analytics | Silent (no tracking) | @kb-labs/analytics-adapter |
| vectorStore | In-memory (empty) | @kb-labs/mind-qdrant |
| llm | Mock responses | @kb-labs/shared-openai |
| embeddings | Deterministic vectors | @kb-labs/shared-openai |
| cache | In-memory Map | @kb-labs/core-redis |
| storage | In-memory Map | @kb-labs/core-fs |
| logger | Console output | @kb-labs/core-pino |
| eventBus | In-memory EventEmitter | Custom (future) |
| invoke | Throws error | Custom (future) |
| artifacts | In-memory storage | Custom (future) |
Core Features also have NoOp fallbacks but may throw errors for critical operations:
workflows.execute()- throws (workflow execution is critical)jobs.submit()- executes synchronously (degraded mode)resources.acquireSlot()- always succeeds (no quota enforcement)
API Reference
initPlatform(config?: PlatformConfig): Promise<PlatformContainer>
Initialize the platform with configuration. Loads adapters and initializes core features.
platform: PlatformContainer
Global singleton container. Access services through properties:
Adapters:
platform.analytics: IAnalyticsplatform.vectorStore: IVectorStoreplatform.llm: ILLMplatform.embeddings: IEmbeddingsplatform.cache: ICacheplatform.storage: IStorageplatform.logger: ILoggerplatform.eventBus: IEventBusplatform.invoke: IInvokeplatform.artifacts: IArtifacts
Core Features:
platform.workflows: IWorkflowEngineplatform.jobs: IJobSchedulerplatform.cron: ICronManagerplatform.resources: IResourceManager
resetPlatform(): void
Reset the platform (for testing).
Adapter Manifest System
NEW: Version 1.0.0 enables multiple adapters of the same type with explicit dependencies and extension points.
Key Features
- ✅ Multiple adapters per type - Run multiple loggers, storages, etc.
- ✅ Explicit dependencies - Declare required/optional adapter dependencies
- ✅ Extension points - Connect adapters via hooks (e.g.,
logger.onLog()) - ✅ Topological sorting - Automatic dependency resolution
- ✅ Circular dependency detection - Fail-fast validation
- ✅ Priority ordering - Control extension execution order
Example: Logger with Extensions
// Configure logger + extensions
await initPlatform({
adapters: {
logger: '@kb-labs/adapters-pino',
logRingBuffer: '@kb-labs/adapters-log-ring-buffer',
logPersistence: '@kb-labs/adapters-log-sqlite',
},
});
// Core logger (type-safe)
platform.logger.info('message');
// Extension adapters (generic)
const buffer = platform.getAdapter<ILogRingBuffer>('logRingBuffer');
const records = buffer?.getRecords();Type System
Core Adapters - Known at compile time:
platform.setAdapter('logger', pinoLogger); // Type: ILogger
const logger = platform.getAdapter('logger'); // ILogger | undefinedExtension Adapters - Dynamic:
platform.setAdapter('logRingBuffer', ringBuffer);
const buffer = platform.getAdapter<ILogRingBuffer>('logRingBuffer');Documentation
See Adapter Manifest Guide for complete documentation.
Rules
- Depends only on core-platform - no other @kb-labs/* packages
- Singleton pattern -
platformis the global instance - Lazy NoOp fallback - if adapter not configured, uses NoOp
- Manifest required - all adapters must export manifest metadata
