🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@inferagraph/core

Package Overview
Dependencies
Maintainers
1
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@inferagraph/core

AI-powered knowledge graph platform with WebGL visualization

Source
npmnpm
Version
0.14.3
Version published
Weekly downloads
81
92.86%
Maintainers
1
Weekly downloads
 
Created
Source

@inferagraph/core

AI-powered knowledge graph platform with WebGL visualization. v0.9.1 — abstract base class renamed DatasourceDataSource for camel-case symmetry with sibling storage packages.

InferaGraph is a self-contained platform that holds graph data, performs AI reasoning via LLM, and renders interactive 3D visualizations. The consuming application is a thin shell that feeds data and displays results — it never invokes the LLM directly.

Features

  • 3D force-directed graph visualization (WebGL/Three.js)
  • Built-in graph store with query, filter, and search
  • Domain-agnostic visibility predicate (uniform across all viz modes — graph, tree, future modes)
  • Streaming chat-as-API with tool calls (apply_filter, highlight, focus, annotate, set_inferred_visibility) auto-dispatched to the renderer
  • Hybrid retrieval — semantic (embeddingStore.searchVector) + keyword + 1-hop graph expansion, weighted-sum merged
  • Cross-encoder rerank — per-candidate LLM relevance scoring with per-conversation cache, top-K kept
  • Multi-turn conversationsConversationStore interface; InMemoryConversationStore ships in core. Pronoun resolution from prior turn's retrievedNodeIds
  • Citation requirement — model is asked to cite every entity inline as [[id]]; the host renders these as clickable links
  • debug chat events — first-class ChatEvent member; surfaced via the new <InferaGraph onDiagnostic> callback for ops-visibility badges
  • onToolCallOutcome — host callback fired after tool-call dispatch so UIs can render "applied / unknown" badges
  • GraphIndexer — reusable indexing engine; one call (embedAll, computeInferredEdges, recomputeInferredEdgesFor, reconcile) handles the whole RAG pipeline. Hosts wire it after data load; library handles the rest
  • embeddingText({contentKeys}) — content body now drives the embedding's body (verbatim, no key: prefix); attribute metadata becomes the header
  • Three-tier embedding progression — keyword search → cache-backed similarity → dedicated EmbeddingStore (now with optional searchVector for vector-native stores)
  • Natural-language query prop — predicate compiled at runtime, ANDed with the explicit filter prop
  • Inferred-edge overlay (RRF over LLM + embeddings + graph signals); toggleable via prop or set_inferred_visibility tool call
  • Drilldown + node detail — + hover affordance, node-click handler, MemoryManager LRU eviction
  • Pluggable LLM providers (Anthropic, OpenAI, Azure AI Foundry); host-blind core
  • React entry point + a separate data entry for Next.js RSC contexts
  • CSS-themable overlays and controls

What's new in 0.12.1

  • AIEngine.buildCitationCandidates no longer memoizes. 0.12.0 keyed the candidate list on store.nodeCount, so an attribute-only edit (e.g. a slug rename with no add/remove) left a stale cache in place and the next chat turn cited the old value. Per-turn rebuild cost is single-digit ms at biblegraph scale (~hundreds to low thousands of nodes); not worth the freshness hazard. The candidate list is now rebuilt fresh on every turn.
  • <ChatText> parses citations as a marked inline extension instead of pre-splitting. 0.12.0 split the text on [[token|matched-text]] first and ran marked.parseInline on each non-citation segment, which broke **[[slug|text]]** (marked saw orphan ** markers on each side of the citation and dropped the emphasis). 0.12.1 registers a citation inline tokenizer on the per-instance Marked, lexes the full text once, and walks the resulting token tree to React nodes — so emphasis, italic, and nested emphasis around a citation now render as <strong><a>...</a></strong> and friends. Codespans (`like this`) intentionally stay opaque: a citation token inside backticks renders as literal text in <code>. Public API is unchanged (text, renderCitation, className); raw HTML is still escaped per 0.10.3.

What's new in 0.12.0

  • Citation wire format becomes [[token|matched-text]]. Both segments are required. The engine now rewrites every entity-name occurrence (not just the first) into the new wire so the host renders one clickable link per mention with the model's exact casing preserved ("the Fall" stays lowercase article). Hard break: tokens without the |matched-text portion are NOT recognized; hosts upgrading from 0.11.x adopt the new shape on consumption.
  • renderCitation: (token, matchedText) => ReactNode. Both arguments required. Hosts wire the anchor's text content from matchedText (model's casing wins) and the URL/path from token. The previous single-argument signature is gone — there is no back-compat path.
  • Citation scope = the whole graph. The injector consumes a { token, title }[] candidate list derived from every node in the store, not just the per-turn rerank top-K. Entities outside the relevant set (e.g. Seth in a turn focused on Adam) still cite when their title appears in the response.
  • System prompt softened. The Citations: block now reads "Write naturally using each entity's name. The engine adds citation links automatically — you do not need to emit [[id]] tokens." The 0.11.0 alarmist "FORBIDDEN / CRITICAL ERROR" framing and the slug-shaped instructional examples are gone. Models write naturally; the engine guarantees the wire shape.
  • Idempotent injector. Running injectCitations on its own output is a no-op: any pre-existing [[token|matched]] collapses to its matched text on the strip pass, then re-emerges identically on the scan pass. Bare [[slug]] model emissions are stripped entirely and treated as garbage.
  • Public surface change is hard-breaking but small. Hosts on 0.11.x update one regex ([[token]][[token|matched-text]]) and one renderCitation signature; tests of the wire format follow.

What's new in 0.11.0

  • Deterministic server-side citation injection. Production gpt-4o-class models routinely ignored the system prompt's [[id]] requirement, leaving the host with uncited streaming text. Soft prompts are not a contract. After the model stream completes, AIEngine.chat now scans the assistant text for first-occurrence titles of every relevantNodes entity and inserts [[citationKey]] directly after the matched span (whole-word, case-insensitive, prefix-aware so Adam Smith is never broken by Adam). When the corrected text differs from what streamed, the engine emits a new text_replace ChatEvent so hosts replace the streamed-incremental bubble with the citation-complete final. Citations become a guaranteed property of the chat pipeline rather than something the model might forget.
  • New ChatEvent variant text_replace. Carries the FULL final text (no diff format). httpTransport reconstructs it from the SSE wire alongside the existing event types. Engines with no post-processing (no citationKey) never emit it, so hosts that don't opt in see zero behavior change.
  • System prompt softened from "REQUIRED, NOT OPTIONAL / FORBIDDEN" to neutral wording. The post-processor handles the contract; the prompt is now belt-and-suspenders ("the host injects citations automatically if you skip them, but emitting them inline produces tighter output"). Existing Cain [[cain]] example and tool-call/citation column guidance are unchanged.
  • Strictly additive on the public surface. Existing ChatEvent consumers that exhaustively switch should add text_replace (or default: assertNever(event)).

What's new in 0.10.3

  • <ChatText> drops isomorphic-dompurify — escapes raw HTML via marked instead. 0.10.2 sanitized parsed HTML by routing it through DOMPurify.sanitize, but isomorphic-dompurify transitively pulls in jsdomhtml-encoding-sniffer@exodus/bytes/encoding-lite.js (ESM-only). Any process that imports the React entry server-side — Next.js SSR routes, Netlify functions, Vercel/Cloudflare workers running the Node runtime — crashed at module init with Error [ERR_REQUIRE_ESM]: require() of ES Module @exodus/bytes/encoding-lite.js. The fix is to make marked itself the sanitizer: a per-instance Marked overrides the html renderer so any raw <script>, <img onerror>, etc. is escaped to text rather than passed through. No DOM library is loaded at any point in the rendering pipeline. Public API is unchanged (ChatText props, citation behavior, default class, <strong>/<em>/<code> output for **bold** / *italic* / `code`); the change is purely an implementation swap. Removes the isomorphic-dompurify dependency from the package and from the consumer's installed tree (~33 transitive packages dropped including jsdom, whatwg-encoding, html-encoding-sniffer, tough-cookie, etc.).

What's new in 0.10.2

  • <ChatText> React component — library now owns chat-text rendering. Hosts streaming assistant replies were each rolling their own markdown + citation parser (Bible Graph shipped one in ChatBubble.tsx last week), pulling marked + isomorphic-dompurify into the host bundle and re-implementing the [[id]] token walk every time. The new component centralizes parse + sanitize + node assembly inside the library so the host's responsibility narrows to CSS styling and citation-link wiring. Pass text (the raw streamed string) plus an optional renderCitation(token) callback that returns the React node a [[token]] should become; the library splits on the citation regex, runs each non-citation segment through marked.parseInline() + DOMPurify, and assembles the result. Default class is .ig-chat-textthemes/default.css and themes/dark.css ship <strong> / <em> / <code> typography rules so consumers get reasonable rendering out of the box; pass className to override. New runtime deps: marked ^18.0.3 and isomorphic-dompurify ^3.12.0 (already present in Bible Graph's bundle, so the migration is a net code reduction host-side).

What's new in 0.10.1

  • httpTransport now reconstructs set_inferred_visibility from the SSE wire. The event has been a member of the ChatEvent union since Phase 5 (inferred-relationship overlay toggle), but reconstructChatEvent never grew a case for it, so a server-side route emitting { type: 'set_inferred_visibility', visible: ... } was silently dropped on the client. Clients now receive both visible: true and visible: false faithfully; payloads with a non-boolean visible field are rejected at the boundary just like the other event reconstructors. Pre-existing tech debt; no public API change.

What's new in 0.10.0

  • Public host-driven dispatch surface (useInferaGraphCommands, useInferaGraphChatContext). Until 0.9.5, hosts could only fire visual operations through chat — useInferaGraphChat() returned a chat iterator and nothing else. Hosts that wanted to reset highlights when a user clicks "Clear conversation" had to wrap the transport, mint a sentinel chat message, and synthesize an empty-ids highlight event by hand. 0.10.0 promotes the renderer's dispatch sink to a public hook. The new useInferaGraphCommands() returns a flat semantic facade (setHighlight, focusOn, applyFilter, setInferredVisibility, annotate, clearAnnotations, resetView, clearVisualState); reach for useInferaGraphChatContext() only when you need to dispatch a ChatEvent variant the facade doesn't expose. Both hooks throw with a clear message when used outside an <InferaGraph> subtree.
  • Three new parameterless ChatEvent variants. clear_visual_state (the "fresh canvas" — drops highlights + annotations + filter, snaps the camera home), reset_view (camera-home only), and clear_annotations (drop every callout). They round-trip over the SSE httpTransport wire too, so a server-side route can fire a reset just like a host UI button. Strictly additive — existing ChatEvent consumers that exhaustively switch should add default: assertNever(event) (or accept the additions explicitly).
  • SceneController.resetView() + clearVisualState(). New public methods on the controller that compose existing surfaces (setHighlight(empty), clearAnnotations(), setFilter(undefined), cameraController.resetRotation()). Call them directly from non-React hosts; the React layer maps the new ChatEvents to these methods.

What's new in 0.9.5

  • Tool-call examples in the chat system prompt are now host-agnostic. The Examples: block previously demonstrated highlight() / focus() calls with literal Bible-Graph slugs (highlight(["garden-of-eden", "adam", "eve"]), focus("noah")). On UUID-keyed hosts those literals contradicted the catalog rows the model was actually reading and obscured the SHAPE of valid tool-call arguments. The examples now use <node-id-N> / <node-id> placeholders wrapped in angle brackets so a model reading the prompt understands the call shape without mistaking the placeholder for a real id. Strictly a prompt-content change; no public API surface moves. The slug-shaped citation example (Cain [[cain]]) under the citationKey-set branch is unchanged — it is intentionally aligned with the catalog's last column per 0.9.4.

What's new in 0.9.4

  • citationKey config aligns the catalog id with the cite-token example. 0.9.3's strengthened citation prompt instructed the model to cite using the catalog's first column, but the concrete example showed a slug-shaped token (Cain [[cain]]) while real catalog rows on UUID-keyed hosts (Bible Graph) carried UUID ids. Tool-use-trained models read the contradiction as "the rule does not match the data" and silently dropped citations for the whole turn. New optional AIEngineConfig.citationKey names a node attribute (e.g., 'slug') whose value is the citation token. When set, the catalog gains a trailing column carrying that value, and the system prompt instructs the model to cite using the LAST column — adding a note that highlight() / focus() still take the FIRST (canonical) column. When unset, behavior matches 0.9.3 except the example uses generic [[node-id-N]] placeholders so it no longer contradicts UUID-shaped catalog ids. Strictly additive — hosts that don't set citationKey see zero behavior change beyond the example wording.

What's new in 0.9.3

  • Citation requirement strengthened. The chat system-prompt's "cite every entity using [[id]]" instruction is now framed as CITATIONS — REQUIRED, NOT OPTIONAL, with a concrete Cain [[cain]] example and an UNCITED, FORBIDDEN counterexample. Tool-use-trained models read soft "cite" verbs as optional; the harder framing matches the pattern already used for highlight() higher in the same prompt and stops models from skipping citations on multi-entity answers.
  • SceneController.setHighlight and focusOn now return { appliedIds, unknownIds }. When the LLM dispatches a highlight() or focus() tool call referencing an id the renderer hasn't seen (model hallucination or stale context), the React layer used to silently swallow the miss. The dispatch path now flows the partition through onToolCallOutcome, so hosts can render "tried to highlight Z but it isn't in the graph" badges. Existing callers that ignored the void return are unaffected at the call site, but dispatch in InferaGraphChatContext is now typed (event) => ToolCallOutcome | undefined — host adapters that conformed to the previous void signature should accept the new return value.

What's new in 0.9.1

  • DatasourceDataSource rename (breaking). The abstract base class exported from @inferagraph/core and @inferagraph/core/data is now DataSource (camel-cased), matching the naming convention used by every sibling storage package (CosmosDataSource, GremlinDataSource, SqlDataSource, RedisDataSource, FileDataSource, LogAnalyticsDataSource). Behavior is unchanged. Hosts that subclass the base directly should rename extends Datasourceextends DataSource and update their import.

What's new in 0.9.0

  • Warmup test-noise silenced. Background ensureEmbeddings() failures (typical with stub providers in unit tests) used to print [InferaGraph AIEngine] ensureEmbeddings failed: ... / embed batch failed: ... to console.warn, polluting test output and forcing hosts to spy on the global console. The warmup path now routes failures through the chat diagnostic surface — the next chat() call yields a ChatEvent of {type:'debug', phase:'warmup-failed', detail} and the buffer drains. No console.warn, no test-runner clutter; failures still surface to hosts that consume the iterable.
  • Nominal-type collision between @inferagraph/core and @inferagraph/core/data fixed. Pre-0.9.0, the two tsup configs each produced an independent declare class AIEngine (and friends) in their .d.ts rollups. Because the class body carries private fields, TypeScript treated them as nominally distinct, so import { AIEngine } from '@inferagraph/core' produced a value that was NOT assignable to a slot typed via @inferagraph/core/data — and vice versa. Folding all three entries into a single tsup config lets the DTS rollup share one chunk per shared class. One AIEngine symbol now flows from every entry; the assignability error disappears for AIEngine, GraphStore, QueryEngine, SearchEngine, GraphIndexer. No source-level import changes are required for consumers that already pick one entry per import — but if you previously worked around the collision with type assertions or aliased imports, you can now drop them.
  • GraphIndexer.computeInferredEdges batched-prompt mode. New optional inferredEdgeBatchSize on GraphIndexerConfig. Default 1 (preserves the existing one-prompt-per-pair behavior). With K > 1, the indexer asks the LLM for K relationship descriptions in a single JSON-array response per batch, dropping provider.complete cost from N calls to ceil(N/K) on the happy path. Defensive parsing: a malformed batch response (non-JSON, missing descriptions array, wrong array length, or call-level error) falls back to per-pair calls for THAT batch only — one bad batch never blocks the whole indexing pass.
  • InMemoryCacheProvider ships in core. New inMemoryCacheProvider() factory + InMemoryCacheProvider class give tests and short-lived dev workflows a Map-backed implementation with optional opt-in TTL and no size eviction. lruCache() remains the production default; @inferagraph/redis-cache-provider continues to ship the persistent variant. Wire via the existing engine.setCache(...).
  • CacheProvider widened. set now accepts an optional { ttlSeconds } for per-call TTL override; delete(key) is added for targeted invalidation (distinct from clear(), which still wipes everything). Existing set(key, value) callers are unaffected — the third argument is optional. InMemoryCacheProvider honors both a construction-time ttlSeconds default and per-call overrides via lazy expiry on get. lruCache accepts the per-call ttlSeconds for signature compatibility but ignores it (its TTL policy is fixed at construction); use construction-time ttl config instead. External implementations such as @inferagraph/redis-cache-provider will satisfy the wider interface in their next bump.

What's new in 0.8.1

  • httpTransport now forwards conversationId from ChatOptions into the request body ({ message, emitToolCalls, conversationId? }). Omitted when undefined so server routes that treat "missing" as "generate a fresh id" still behave correctly.
  • useInferaGraphChat().chat(message, { conversationId }) accepts a per-call conversationId; the hook forwards it to the active transport so hosts no longer need to bypass the hook to thread conversation memory through their server route.

What's new in 0.8.0

  • LLMMessage / LLMRole types for structured-roles chat (already in 0.7.x; now stable surface)
  • EmbeddingStore.searchVector?(queryEmbedding, {top, container}) — additive optional method; InMemoryEmbeddingStore implements via linear-scan cosine
  • ChatEvent gains {type:'debug', phase, detail?, counters?, conversationId?}
  • AIEngineConfig gains embeddingContentKeys, chatRerankEnabled, chatRerankCandidates, chatRerankTopK, priorTurnLimit
  • AIEngine.setConversationStore(store) + chat(message, {conversationId})
  • AIEngine.buildChatMessages adds an Edges block, an Inferred-relationships block, a pronoun-resolution block (when applicable), and the citation requirement
  • emitWithFallbacks rewritten as a pure reducer; empty-highlight substitution draws from per-query retrieval, zero-text synthesis grounds in the first retrieved node's content (no more Showing X, Y, Z catalog roll-up)
  • <InferaGraph onDiagnostic onToolCallOutcome> props
  • Re-exports: LLMMessage, LLMRole, ConversationStore, ConversationTurn, inMemoryConversationStore, SearchVectorHit, GraphIndexer, GraphIndexerConfig, IndexerProgress, DEFAULT_EMBEDDING_CONTENT_KEYS, EmbeddingTextOptions, ToolCallOutcome

Installation

pnpm add @inferagraph/core

Two entry points:

  • @inferagraph/core / @inferagraph/core/react — React layer (client-side; touches React.createContext)
  • @inferagraph/core/data — server-safe data layer (RSC, route handlers)

React component

import { InferaGraph } from '@inferagraph/core/react';
import { openaiProvider } from '@inferagraph/openai-provider';

<InferaGraph
  data={data}
  llm={openaiProvider({ apiKey: process.env.OPENAI_KEY! })}
  query="people from the Patriarchs era"
  onNodeClick={(id, node) => openDetailDialog(id, node)}
  onExpandRequest={(id) => /* host can override; default expands neighbors */}
  maxNodes={1000}
/>

Selected props (see InferaGraphProps for the full list)

PropTypeNotes
dataGraphDataInitial nodes + edges.
layoutLayoutMode'graph' (default) or 'tree'.
filter(node) => booleanDomain-agnostic visibility predicate. Same predicate applies in every viz mode.
querystringNLQ; LLM compiles to predicate, ANDed with filter. Requires llm.
llmLLMProviderPre-configured provider instance. Library is host-blind from this point.
cacheCacheProviderOptional response cache. Default is no cache.
embeddingStoreEmbeddingStoreOptional Tier-3 vector store; default inMemoryEmbeddingStore() is exported.
transportTransportOverride the default in-process chat transport (e.g., HTTP proxy).
showInferredEdgesbooleanToggle the dashed inferred-edge overlay. Default false.
onChat(event) => voidReceives text + done events; tool calls dispatch silently to the renderer.
slugResolverSlugResolverPhase 6 — translates input slugs to canonical NodeIds for hooks.
maxNodesnumberPhase 6 — soft cap; MemoryManager LRU-evicts oldest non-protected nodes.
onNodeClick(id, node) => voidPhase 6 — fires on node-body clicks (post-slug resolution).
onExpandRequest(id) => voidPhase 6 — fires on + affordance clicks. Default handler calls useInferaGraphNeighbors().expand(id).
nodeColors / edgeColorsRecord<string,string>Type → color maps. Function variants via nodeColorFn / edgeColorFn.
incomingEdgeLabels / outgoingEdgeLabelsEdgeLabelMapTooltip relationship phrasing maps.

Hooks (@inferagraph/core/react)

  • useInferaGraph() — store + AIEngine handles
  • useInferaGraphChat() — streaming chat iterator
  • useInferaGraphSearch() — keyword / similarity search
  • useInferaGraphContent(idOrSlug) — fetch node detail content (uses slugResolver if configured)
  • useInferaGraphNeighbors() — expand / collapse drilldown
  • GraphProvider — context provider; needed only for advanced multi-instance setups
  • createReactNodeRenderFn / createReactTooltipRenderFn — bridges for custom React node / tooltip components

DataAdapter contract

Every datasource plugin (and any custom one a host writes) implements seven methods:

interface DataAdapter {
  getInitialView(config?): Promise<GraphData>;
  getNode(id): Promise<NodeData | undefined>;
  getNeighbors(id, depth?): Promise<GraphData>;
  findPath(fromId, toId): Promise<GraphData>;
  search(query, pagination?): Promise<PaginatedResult<NodeData>>;
  filter(filter, pagination?): Promise<PaginatedResult<NodeData>>;
  getContent(id): Promise<ContentData | undefined>;
}

LLM Providers

Hosts inject one provider instance at construction. The library never imports a provider SDK directly — the provider package owns its dependency.

pnpm add @inferagraph/anthropic-provider     # Claude (+ optional Voyage embeddings)
pnpm add @inferagraph/openai-provider        # OpenAI / Azure OpenAI / OpenRouter / GitHub Models
pnpm add @inferagraph/azure-foundry-provider # Azure AI Foundry catalog

Anthropic has no native embeddings endpoint — pass an optional voyage config to its provider for embedding support, or mix-and-match (Anthropic for chat + a different provider's embed).

Cache providers

  • Built-in lruCache() — in-process, default (maxEntries: 500, ttl: '24h').
  • @inferagraph/redis-cache-provider — Redis-backed for shared / multi-process caches.

The cache prop also serves as Tier-2 embedding storage when the configured provider implements embed() and no dedicated embeddingStore is supplied.

License

MIT

Keywords

knowledge-graph

FAQs

Package last updated on 08 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts