Server-only Tag Engine that extends @memberjunction/tag-engine-base via composition and adds semantic embedding support for tag resolution. Uses SimpleVectorService to embed all tags at startup for sub-millisecond local cosine similarity matching.
Server-side only. For client-side tag operations (hierarchy, lookups, CRUD), use @memberjunction/tag-engine-base directly.
Read first: Taxonomy & Tagging Guide — the canonical design doc for the tag taxonomy, the 4+1-tier resolver, scoping, governance, the suggestion queue, and Tag Health. This README is the API reference; the guide is the why and how.
npm install @memberjunction/tag-engine
import { TagEngine } from '@memberjunction/tag-engine';
await TagEngine.Instance.Config(false, contextUser);
Config() performs the following steps:
TagEngineBase (all Tags and TaggedItems from the database).AIEngine.SimpleVectorService for instant similarity search.Safe to call multiple times; subsequent calls are no-ops unless forceRefresh is true. Concurrent calls are coalesced (second caller awaits the first).
All TagEngineBase methods are available directly on TagEngine.Instance:
| Method | Description |
|---|---|
GetTagByID(id) |
Find tag by ID (case-insensitive UUID) |
GetTagByName(name) |
Find tag by name (case-insensitive string) |
GetChildTags(parentID) |
Get direct children of a tag |
GetSubtree(rootID) |
Get all descendants recursively |
GetTaggedItemsForRecord(entityID, recordID) |
Get all tagged items for a record |
GetTaxonomyTree(rootID?) |
Build hierarchical TagTreeNode tree |
CreateTag(name, displayName, parentID, description, contextUser) |
Create and cache a new tag |
CreateTaggedItem(tagID, entityID, recordID, weight, contextUser) |
Create or update a tagged item |
| Property | Type | Description |
|---|---|---|
Tags |
MJTagEntity[] |
All loaded Tag entities (delegated from TagEngineBase) |
TaggedItems |
MJTaggedItemEntity[] |
All loaded TaggedItem entities (delegated) |
TagVectorService |
SimpleVectorService<TagEmbeddingMetadata> | null |
In-memory vector index of tag embeddings, or null if no embedding model is available |
Loaded |
boolean |
True if both the base engine and embeddings are loaded |
ResolveTag(tagText, weight, mode, rootID, threshold, contextUser): Promise<MJTagEntity | null>The primary method for mapping free-text tag strings to formal Tag records. Uses a three-step resolution strategy:
Step 1 -- Exact Name Match (fast path)
Case-insensitive string comparison against all loaded tags. If a match is found and it falls within the optional subtree constraint, it is returned immediately. No embedding computation needed.
Step 2 -- Semantic Similarity Search
If no exact match, embeds the tag text and performs cosine similarity search against the in-memory tag vector index. Results are filtered by the threshold score and optionally constrained to a subtree rooted at rootID.
Step 3 -- Mode-Based Fallback
If no match is found:
| Mode | Behavior |
|---|---|
constrained |
Returns null. No new tags are created. |
auto-grow |
Creates a new tag as a child of rootID and adds its embedding to the vector service. |
free-flow |
Creates a new root-level tag (no parent) and adds its embedding to the vector service. |
Parameters:
| Parameter | Type | Description |
|---|---|---|
tagText |
string |
The free-text tag to resolve |
weight |
number |
Relevance weight (0.0--1.0), used if a new tag is created |
mode |
'constrained' | 'auto-grow' | 'free-flow' |
Resolution mode |
rootID |
string | null |
Subtree root for scoping. In auto-grow, also the parent for new tags |
threshold |
number |
Minimum cosine similarity (0--1) for semantic match acceptance |
contextUser |
UserInfo |
Server-side user context |
Example:
const tag = await TagEngine.Instance.ResolveTag(
'neural networks', // tagText
0.85, // weight
'auto-grow', // mode
rootTagID, // rootID (or null)
0.9, // threshold
contextUser
);
// tag is either an existing matched Tag, a newly created Tag, or null (constrained mode only)
TagEngine automatically discovers the best embedding model at startup by:
AIEngine.Instance.Models for models with AIModelType === 'Embeddings'.InputTokenLimit ascending to pick the smallest (cheapest/fastest) model.ModelVendor for that model to get the DriverClass and APIName.If no embedding model is available, the engine logs a status message and operates in degraded mode: exact-name matching still works, but semantic similarity search is disabled. The TagVectorService property will be null.
| Condition | Behavior |
|---|---|
| No tags in database | Skips embedding generation entirely |
| No embedding model configured | Semantic matching disabled; exact-name matching still works |
| Embedding fails for a single tag | That tag is skipped; other tags are still embedded |
| Vector service unavailable during ResolveTag | Falls through to mode-based fallback (create or return null) |
Each entry in the vector service carries metadata:
interface TagEmbeddingMetadata {
Name: string; // The tag's internal name
ParentID: string | null; // Parent tag ID, or null for root tags
}
The embedding text for each tag is composed as "Name: Description" (or just "Name" if no description exists), providing richer semantic representation.
@memberjunction/tag-engine-base -- Client+server shared engine (hierarchy, CRUD, taxonomy serialization)@memberjunction/content-autotagging -- Content autotagging pipeline that uses TagEngine for taxonomy bridging@memberjunction/ai-vectors-memory -- SimpleVectorService for in-memory vector operationsSee the Content Autotagging Guide for full pipeline documentation including the tag taxonomy bridge, prompt structure, and configuration.