# @memberjunction/ai-engine-base
Base AI Engine package for MemberJunction. Provides a comprehensive metadata cache for all AI-related entities -- models, vendors, prompts, agents, configurations, modalities, permissions, and more. This package extends `BaseEngine` to load and cache AI metadata in a single batch, making it available on both server and client without duplicating data loading logic.
## Architecture
```mermaid
graph TD
subgraph Dependencies
CORE["@memberjunction/core
BaseEngine"]
style CORE fill:#2d6a9f,stroke:#1a4971,color:#fff
CE["@memberjunction/core-entities"]
style CE fill:#2d6a9f,stroke:#1a4971,color:#fff
ACP["@memberjunction/ai-core-plus
Extended Entities"]
style ACP fill:#2d6a9f,stroke:#1a4971,color:#fff
end
AIB["AIEngineBase
Singleton Metadata Cache"]
style AIB fill:#2d8659,stroke:#1a5c3a,color:#fff
subgraph "Cached Metadata"
M["Models & Model Types"]
style M fill:#7c5295,stroke:#563a6b,color:#fff
V["Vendors & Model Vendors"]
style V fill:#7c5295,stroke:#563a6b,color:#fff
P["Prompts, Categories & Types"]
style P fill:#7c5295,stroke:#563a6b,color:#fff
A["Agents, Types & Relationships"]
style A fill:#7c5295,stroke:#563a6b,color:#fff
CFG["Configurations & Params"]
style CFG fill:#b8762f,stroke:#8a5722,color:#fff
MOD["Modalities & Limits"]
style MOD fill:#b8762f,stroke:#8a5722,color:#fff
PERM["Permissions & Credentials"]
style PERM fill:#b8762f,stroke:#8a5722,color:#fff
end
CORE --> AIB
CE --> AIB
ACP --> AIB
AIB --> M
AIB --> V
AIB --> P
AIB --> A
AIB --> CFG
AIB --> MOD
AIB --> PERM
SRV["AIEngine (Server)"]
style SRV fill:#2d6a9f,stroke:#1a4971,color:#fff
AIB --> SRV
```
## Installation
```bash
npm install @memberjunction/ai-engine-base
```
## Key Exports
### AIEngineBase (Singleton)
The core class that loads and caches all AI metadata. Access via `AIEngineBase.Instance`.
```typescript
import { AIEngineBase } from '@memberjunction/ai-engine-base';
// Initialize (typically at app startup)
await AIEngineBase.Instance.Config(false, contextUser);
// Access cached metadata
const models = AIEngineBase.Instance.Models;
const agents = AIEngineBase.Instance.Agents;
const prompts = AIEngineBase.Instance.Prompts;
```
#### Cached Entity Collections
| Property | Entity | Description |
|---|---|---|
| `Models` | AI Models | All registered AI models with extended properties |
| `ModelTypes` | AI Model Types | Model type categories (LLM, Embeddings, etc.) |
| `Vendors` | MJ: AI Vendors | AI service providers |
| `ModelVendors` | MJ: AI Model Vendors | Model-vendor associations |
| `Prompts` | AI Prompts | All prompt definitions with category associations |
| `PromptModels` | MJ: AI Prompt Models | Prompt-model associations |
| `PromptTypes` | AI Prompt Types | Prompt type categories |
| `PromptCategories` | AI Prompt Categories | Hierarchical prompt organization |
| `Agents` | AI Agents | All agent definitions with actions and notes |
| `AgentTypes` | MJ: AI Agent Types | Agent type definitions |
| `AgentActions` | AI Agent Actions | Actions associated with agents |
| `AgentPrompts` | MJ: AI Agent Prompts | Prompts associated with agents |
| `AgentSteps` | MJ: AI Agent Steps | Flow agent step definitions |
| `AgentStepPaths` | MJ: AI Agent Step Paths | Transitions between flow steps |
| `AgentRelationships` | MJ: AI Agent Relationships | Sub-agent relationships |
| `AgentPermissions` | MJ: AI Agent Permissions | User/role permission grants |
| `AgentConfigurations` | MJ: AI Agent Configurations | Semantic presets (Fast, High Quality) |
| `Configurations` | MJ: AI Configurations | Global AI configurations with inheritance |
| `ConfigurationParams` | MJ: AI Configuration Params | Key-value parameters for configurations |
| `ModelCosts` | MJ: AI Model Costs | Cost tracking per model/vendor |
| `ModelPriceTypes` | MJ: AI Model Price Types | Price type definitions |
| `ModelPriceUnitTypes` | MJ: AI Model Price Unit Types | Unit type definitions |
| `CredentialBindings` | MJ: AI Credential Bindings | Credential bindings for vendors/models |
| `Modalities` | MJ: AI Modalities | Input/output modality definitions |
| `AgentModalities` | MJ: AI Agent Modalities | Agent modality support |
| `ModelModalities` | MJ: AI Model Modalities | Model modality support |
| `VectorDatabases` | Vector Databases | Vector database configurations |
| `ArtifactTypes` | MJ: Artifact Types | Artifact type definitions |
| `AgentPairedAgents` | MJ: AI Agent Paired Agents | Realtime co-agent → target-agent pairing junction |
| `AgentChannels` | MJ: AI Agent Channels | Interactive-channel registry (plugin classes, transport) |
> **Realtime pairing + channel registries (new):** `AgentPairedAgents` (`MJ: AI Agent Paired Agents`) and `AgentChannels` (`MJ: AI Agent Channels`) are cached as unfiltered local datasets like every other small metadata table here. Pairing rows constrain which target agents a Realtime co-agent may front (`Sequence` ordering, at most one `IsDefault` per co-agent; zero rows = universal co-agent), and channel rows declare the interactive-channel surfaces (e.g. the live Whiteboard) with their server/client plugin class keys and `IsActive` flag. Consumers (the voice picker/session services, `RealtimeChannelServerHost`, and `RealtimeClientSessionResolver`) read these getters and filter in memory instead of issuing per-call RunViews — BaseEngine's save/delete/remote-invalidate reactivity keeps both caches fresh.
#### Convenience Methods
```typescript
// Get the highest-power model of a given type
const bestLLM = await AIEngineBase.Instance.GetHighestPowerLLM('OpenAI', contextUser);
const bestEmbedding = await AIEngineBase.Instance.GetHighestPowerModel('OpenAI', 'Embeddings', contextUser);
// Get agent by name
const agent = AIEngineBase.Instance.GetAgentByName('Customer Support Agent');
// Get sub-agents (children + relationships)
const subAgents = AIEngineBase.Instance.GetSubAgents(agentId, 'Active');
// Configuration presets
const presets = AIEngineBase.Instance.GetAgentConfigurationPresets(agentId);
const defaultPreset = AIEngineBase.Instance.GetDefaultAgentConfigurationPreset(agentId);
```
#### Fast Lookups (O(1) indexes + memoized helpers)
The cached collections are plain arrays, but the engine also exposes lazily-built lookup
indexes and memoized helpers so hot paths (model selection, credential resolution) don't
re-scan them on every call. All indexes are rebuilt automatically when the metadata reloads.
```typescript
const eng = AIEngineBase.Instance;
// O(1) by-ID lookups (keys are NormalizeUUID'd — case/whitespace safe)
const model = eng.ModelsByID.get(NormalizeUUID(modelId));
const vendor = eng.VendorsByID.get(NormalizeUUID(vendorId));
const config = eng.ConfigurationsByID.get(NormalizeUUID(configId));
const type = eng.ModelTypesByID.get(NormalizeUUID(typeId));
// Grouped indexes
const vendorsForModel = eng.ModelVendorsByModelID.get(NormalizeUUID(modelId)) ?? [];
const modelsForPrompt = eng.PromptModelsByPromptID.get(NormalizeUUID(promptId)) ?? [];
// Inference-provider check (memoized vendor-type lookup; Model-Developer fallback)
if (eng.IsInferenceProvider(modelVendor)) { /* runs the model, not just develops it */ }
const inferenceTypeId = eng.InferenceProviderTypeID; // memoized
```
> When you already hold a model entity, prefer `model.ModelVendors` (the per-model vendor
> array the engine attaches at load) over `ModelVendorsByModelID`. The index exists for callers
> that only have a ModelID.
#### Configuration Inheritance
Configurations support parent-child inheritance chains:
```typescript
// Get the full inheritance chain (child -> parent -> grandparent)
const chain = AIEngineBase.Instance.GetConfigurationChain(configId);
// Get parameters with inheritance (child overrides parent)
const params = AIEngineBase.Instance.GetConfigurationParamsWithInheritance(configId);
```
#### Model Cost Tracking
```typescript
// Get active cost for a model/vendor combination
const cost = AIEngineBase.Instance.GetActiveModelCost(modelId, vendorId, 'Realtime');
```
#### Credential Bindings
```typescript
// Get credential bindings for a vendor
const bindings = AIEngineBase.Instance.GetCredentialBindingsForTarget('Vendor', vendorId);
// Check if bindings exist
const hasBindings = AIEngineBase.Instance.HasCredentialBindings('ModelVendor', modelVendorId);
```
### Modality System
The modality system tracks which input/output types (Text, Image, Audio, Video, File) agents and models support.
```typescript
// Check if an agent supports image input
const supportsImages = AIEngineBase.Instance.AgentSupportsModality(agentId, 'Image', 'Input');
// Check if agent accepts any attachments
const supportsAttachments = AIEngineBase.Instance.AgentSupportsAttachments(agentId);
// Get aggregated attachment limits for UI configuration
const limits = AIEngineBase.Instance.GetAgentAttachmentLimits(agentId, modelId);
// limits.enabled, limits.maxAttachments, limits.maxAttachmentSizeBytes, limits.acceptedFileTypes
```
### Agent Permission Helper
```typescript
// Check individual permissions
const canView = await AIEngineBase.Instance.CanUserViewAgent(agentId, user);
const canRun = await AIEngineBase.Instance.CanUserRunAgent(agentId, user);
// Get all permissions at once
const perms = await AIEngineBase.Instance.GetUserAgentPermissions(agentId, user);
// perms.canView, perms.canRun, perms.canEdit, perms.canDelete, perms.isOwner
// Get all accessible agents for a user
const agents = await AIEngineBase.Instance.GetAccessibleAgents(user, 'run');
```
### Additional Exports
| Export | Purpose |
|---|---|
| `ModalityLimits` | Resolved limits for a specific modality (size, count, dimension, formats) |
| `AgentAttachmentLimits` | Aggregated attachment limits for UI components |
| `PriceUnitTypes` | Price unit type utilities |
| `AIAgentPermissionHelper` | Static helper for agent permission checks |
| `EffectiveAgentPermissions` | Complete permission set for a user/agent combination |
| `AICredentialBindingEntityExtended` | Extended credential binding entity |
## Skill Gating
`AIEngineBase` is the single source of truth for which skills an agent may use, via two methods with distinct purposes:
| Method | Question it answers | Gates applied |
|---|---|---|
| `GetSkillsForAgent(agent, user?)` | May this agent+user use this skill at all? (**availability**) | `AIAgent.AcceptsSkills` (None/All/Limited) × `AISkill.Status='Active'` × per-grant `MJ: AI Agent Skills.Status` (Limited only) × user Run permission (when `user` supplied) |
| `GetAutoActivatableSkillsForAgent(agent, user?)` | May this agent **self-activate** this skill? (**trigger**) | Everything above **plus the double activation gate**: `AIAgent.SkillActivationMode === 'Auto'` AND `AISkill.ActivationMode === 'Auto'` (both default `'RequestedOnly'`) |
Use the availability set for the user-requested path (`/skill` mentions → `ExecuteAgentParams.requestedSkillIDs`) and for pickers/tooling; use the auto set for anything the *agent* triggers on its own judgment (the prompt catalog, `Skill`-step validation). Because both `ActivationMode` defaults are `RequestedOnly`, the Auto × Auto "super agent" posture is always a deliberate double opt-in.
Bundle membership is resolved by ID via `GetSkillActionIDs(skillID)` / `GetSkillSubAgentIDs(skillID)`; skill permission rows are cached on `SkillPermissions` and evaluated by `AISkillPermissionHelper` (open-by-default). Full architecture: [Agent Skills & Plan Mode Guide](../../../guides/AGENT_SKILLS_AND_PLAN_MODE_GUIDE.md).
## Dependencies
- `@memberjunction/core` -- BaseEngine, Metadata, RunView
- `@memberjunction/core-entities` -- Generated entity classes
- `@memberjunction/ai` -- Core AI abstractions
- `@memberjunction/ai-core-plus` -- Extended entity classes
- `@memberjunction/global` -- Class factory
- `@memberjunction/templates-base-types` -- Template engine integration