npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@typegraph-ai/sdk

v0.6.0

Published

TypeScript SDK for retrieval, knowledge graph, and cognitive memory for AI agents

Readme

@typegraph-ai/sdk

The TypeGraph SDK is the main TypeScript API for a business context graph: documents, events, threads, entities, facts, memory, jobs, policies, telemetry, and hybrid search from one client.

This package README documents the current SDK surface. Use the repository root README for the product-level overview.

Install

pnpm add @typegraph-ai/sdk

For self-hosted Postgres:

pnpm add @typegraph-ai/sdk @typegraph-ai/adapter-pgvector @ai-sdk/gateway @neondatabase/serverless

Core Model

TypeGraph is tenant-scoped. tenantId is configured once on typegraphInit or typegraphDeploy, and it is the hard graph/data boundary.

Use separate tenant IDs when you need separate graph universes. Do not use separate tenant IDs for customer accounts inside one B2B product intelligence graph if you need cross-customer questions like "Which customers are blocked by SSO issues?" Model those customers as entities instead.

import {
  AgentId,
  GroupId,
  TenantId,
  UserId,
  entityRef,
  typegraphInit,
} from '@typegraph-ai/sdk'

const tg = await typegraphInit({
  apiKey: process.env.TYPEGRAPH_API_KEY!,
})

Graphs are the logical knowledge boundaries inside a tenant. The default bucket is public, the default graph is public, and the public bucket writes to the public graph. Buckets own write routing; ingest calls choose a bucket, not an ad hoc graph.

const tg = await typegraphInit({
  apiKey: process.env.TYPEGRAPH_API_KEY!,
  tenantId: TenantId('tenant_acme'),
  graphs: {
    public: { access: 'public' },
    internal: {
      extends: ['public'],
      access: {
        read: { groups: [GroupId('employees')] },
        write: { groups: [GroupId('employees')] },
      },
    },
  },
  buckets: {
    public: { graph: 'public' },
    gong: { name: 'Gong Calls', graph: 'internal', graphExtraction: true },
  },
})

Per-call actor identity lives under one key: context.

const context = {
  userId: UserId('dana'),
  groupId: GroupId('success'),
  agentId: AgentId('successbot'),
}

Graph access belongs on graph config, not on individual records. Event participants are provenance and business graph context only; they never grant read access automatically.

Cloud Quick Start

import { GroupId, UserId, typegraphInit } from '@typegraph-ai/sdk'

const tg = await typegraphInit({
  apiKey: process.env.TYPEGRAPH_API_KEY!,
  graphs: {
    public: { access: 'public' },
    internal: {
      extends: ['public'],
      access: {
        read: { groups: [GroupId('it')] },
        write: { groups: [GroupId('it')] },
      },
    },
  },
  buckets: {
    public: { graph: 'public' },
    it: { name: 'IT Knowledge', graph: 'internal', graphExtraction: true },
  },
})

await tg.document.ingest(
  {
    id: 'notion:sso-handbook',
    name: 'SSO setup handbook',
    description: 'Internal handbook section for SSO setup.',
    content: 'Employees configure SSO from Admin > Security > SSO.',
    metadata: { provider: 'notion', space: 'internal-it' },
  },
  {
    context: {
      userId: UserId('dana'),
      groupId: GroupId('it'),
    },
    bucketId: 'it',
  },
)

const response = await tg.search('How do employees configure SSO?', {
  graph: 'internal',
  context: {
    userId: UserId('dana'),
    groupId: GroupId('it'),
  },
  resources: ['documents', 'facts', 'entities'],
  weights: { semantic: 1, bm25: 0.7, graph: 0.5, recency: 0.3 },
  promptBuilder: {
    format: 'xml',
    sections: ['chunks', 'facts', 'entities'],
  },
})

console.log(response.prompt)

Self-Hosted Quick Start

import { gateway } from '@ai-sdk/gateway'
import { neon } from '@neondatabase/serverless'
import { PgVectorAdapter } from '@typegraph-ai/adapter-pgvector'
import { TenantId, typegraphDeploy, typegraphInit } from '@typegraph-ai/sdk'

const sql = neon(process.env.DATABASE_URL!)
const vectorStore = new PgVectorAdapter({ sql })

const config = {
  tenantId: TenantId('tenant_acme'),
  vectorStore,
  embedding: {
    model: gateway.embeddingModel('openai/text-embedding-3-small'),
    dimensions: 1536,
  },
  searchEmbedding: {
    model: gateway.embeddingModel('openai/text-embedding-3-small'),
    dimensions: 1536,
  },
  llm: {
    model: gateway.languageModel('openai/gpt-4.1-mini'),
  },
}

await typegraphDeploy(config)
const tg = await typegraphInit(config)

typegraphDeploy(config) creates storage objects. typegraphInit(config) is the lightweight app-runtime initializer. Self-hosted users should not call public graph or memory bridge constructors; vectorStore + embedding + llm is enough for graph extraction, graph APIs, and memory APIs when the adapter supports the required storage capabilities.

Documents

Documents are durable long-form content with chunks and embeddings.

await tg.document.ingest(
  [
    {
      id: 'zendesk:article:42',
      name: 'SAML troubleshooting',
      description: 'Known SAML setup failures and resolutions.',
      content: articleBody,
      metadata: { provider: 'zendesk', locale: 'en-US' },
    },
    {
      id: 'notion:page:pricing-faq',
      name: 'Pricing FAQ',
      description: 'Internal pricing and packaging answers.',
      content: pricingFaq,
      metadata: { provider: 'notion' },
    },
  ],
  {
    bucketId: 'support',
    context: {
      userId: UserId('dana'),
    },
  },
)

Document inputs use the standard primary fields:

{
  id?: string
  name: string
  description?: string
  url?: string | null
  content: string
  metadata?: Record<string, unknown>
}

Events

Events are time-anchored business occurrences. They can contain short event content and can attach documents, such as meeting transcripts or support exports.

await tg.event.ingest(
  {
    id: 'gong:meeting:123',
    name: 'Acme discovery call',
    description: 'Acme reported an SSO redirect loop blocking enterprise rollout.',
    url: 'https://gong.example.com/calls/123',
    occurredAt: new Date('2026-05-08T17:00:00Z'),
    participants: [
      entityRef('organization', 'org_acme'),
      entityRef('product_area', 'auth'),
      entityRef('issue', 'sso_redirect_loop'),
      entityRef('user', 'dana'),
    ],
    documents: [
      {
        id: 'gong:transcript:123',
        name: 'Acme discovery call transcript',
        description: 'Transcript from the Acme discovery call.',
        url: 'https://gong.example.com/calls/123/transcript',
        content: transcriptText,
        metadata: { provider: 'gong' },
      },
    ],
    metadata: { provider: 'gong', meetingId: '123' },
  },
  {
    bucketId: 'gong',
    context: {
      userId: UserId('dana'),
      groupId: GroupId('success'),
    },
  },
)

In this example, organization:org_acme, product_area:auth, and issue:sso_redirect_loop are graph/business participants. The gong bucket routes the write into the graph configured for that bucket. Product can ask cross-customer questions when it searches the graph that contains those records.

event.ingest() accepts one event or an array. Attached documents inherit the selected bucket and therefore the selected bucket's graph.

Threads

Threads are ordered containers. Turns are intentionally simple message records:

await tg.thread.upsert(
  {
    id: 'thread_123',
    name: 'Acme renewal workflow',
    description: 'Working thread for Acme renewal risk and next steps.',
    url: 'https://slack.example.com/archives/C123',
    metadata: { crmAccountId: '001-acme' },
  },
  { bucketId: 'gong', context: { groupId: GroupId('success') } },
)

await tg.thread.addTurn(
  'thread_123',
  {
    role: 'user',
    content: 'Acme needs a workaround for the SSO redirect loop before Friday.',
    url: 'https://slack.example.com/archives/C123/p456',
    timestamp: new Date(),
    metadata: { source: 'slack' },
  },
  {
    context: {
      userId: UserId('dana'),
      threadId: 'thread_123',
      groupId: GroupId('success'),
    },
    bucketId: 'gong',
  },
)

thread.addTurn() creates a linked event internally. A turn does not have name, description, or per-turn access fields.

Search

Search separates identity, target resources, scoring weights, and prompt assembly.

const response = await tg.search('Which customers are blocked by SSO issues?', {
  graph: 'internal',
  context: {
    userId: UserId('dana'),
    groupId: GroupId('product'),
  },
  buckets: ['gong', 'zendesk', 'salesforce'],
  resources: ['events', 'documents', 'facts', 'entities'],
  weights: {
    semantic: 1,
    bm25: 0.7,
    graph: 0.8,
    recency: 0.3,
  },
  fusion: { method: 'rrf', k: 60 },
  rerank: { topK: 20 },
  limit: 10,
  promptBuilder: {
    format: 'markdown',
    sections: ['facts', 'entities', 'chunks'],
    maxTotalTokens: 6000,
  },
  explain: true,
})

response.results.chunks
response.results.facts
response.results.entities
response.prompt
response.promptStats
response.explanation

In self-hosted mode, rerank uses the reranker passed to typegraphInit(). When reranking is requested without a configured reranker, search logs a warning and falls back to fused results. When a reranker is configured, TypeGraph overfetches candidates before reranking, then slices chunks to limit. Reranking is an internal ordering step over QueryChunkResult[]; tg.search() still returns the normal QueryResponse shape.

Provider wrappers should map provider rankings back to the original chunk candidates:

import { cohere } from '@ai-sdk/cohere'
import { rerank } from 'ai'
import type { QueryChunkResult, Reranker } from '@typegraph-ai/sdk'

const cohereReranker: Reranker<QueryChunkResult> = {
  name: 'cohere-rerank',
  async rerank(query, candidates, opts) {
    const { ranking } = await rerank({
      model: cohere.reranking('rerank-v3.5'),
      query,
      documents: candidates,
      topN: opts?.topK,
      abortSignal: opts?.abortSignal,
    })

    return ranking
      .map(item => candidates[item.originalIndex])
      .filter((candidate): candidate is QueryChunkResult => !!candidate)
  },
}

Raw Cohere responses expose results[].index and relevance_score; Vercel AI SDK rerank() exposes ranking[].originalIndex, score, and document. TypeGraph adapters return reordered QueryChunkResult[], not raw provider responses. scores.output.reranker is TypeGraph's normalized rank-position score.

Search resources:

type SearchResource =
  | 'documents'
  | 'events'
  | 'threads'
  | 'entities'
  | 'facts'

Search weights:

type SearchWeights = {
  semantic?: number | false
  bm25?: number | false
  graph?: number | false
  recency?: number | false
}

Defaults are { semantic: 1, bm25: 0.7, graph: 0.5, recency: 0.3 }. Set a weight to false to disable that scoring signal.

Use promptBuilder when you want an LLM-ready string. The generated string is returned as response.prompt; prompt assembly statistics are returned as response.promptStats.

abortSignal is part of the public options shape and custom embedders or extractors can honor it through their own contracts. Treat full end-to-end adapter cancellation as best-effort until every storage and model path supports it.

const controller = new AbortController()

await tg.document.ingest(document, {
  context: { userId: UserId('dana') },
  abortSignal: controller.signal,
})

Embedding

Self-hosted config uses final Embedder naming. Ingest and search embedders can be configured separately as long as they produce vectors in the same space.

type EmbedInput = {
  texts: string[]
  inputType?: 'document' | 'search'
  outputDimensions?: number
  abortSignal?: AbortSignal
}

interface Embedder {
  name: string
  dimensions: number
  maxBatchSize?: number
  supportsAsymmetric?: boolean
  embed(input: EmbedInput): Promise<number[][]>
}
await typegraphInit({
  vectorStore,
  embedding: documentEmbedder,
  searchEmbedding,
  additionalEmbeddings: [specializedLegalEmbedder],
})

Bucket config can override the defaults with embeddingModel and searchEmbeddingModel.

Extraction And Ontology

graphExtraction: true runs the configured extractor. If you pass llm, TypeGraph builds its internal default extractor. If you pass extractor, your extractor wins. Single-pass, two-pass, and prompt staging are not public API.

await typegraphInit({
  vectorStore,
  embedding,
  llm: { model: gateway.languageModel('openai/gpt-4.1-mini') },
  extractor: customExtractor,
  ontology: {
    version: '2026-05-08',
    profiles: ['saas'],
    entities: {
      organization: {
        description: 'Customer, vendor, partner, or internal org',
        vocabulary: [{ vocabulary: 'schema.org', id: 'Organization', uri: 'https://schema.org/Organization' }],
      },
      product_area: { description: 'Owned product surface or component' },
      issue: { description: 'Product, support, security, or implementation issue' },
    },
    relations: {
      experiences_issue: {
        from: ['organization'],
        to: ['issue'],
        description: 'Organization is affected by an issue',
      },
    },
  },
})

Custom extractors implement:

interface Extractor {
  name: string
  capabilities: ExtractorCapabilities
  extract(input: ExtractorInput, ctx: ExtractorContext): Promise<ExtractionResult>
}

Ontology is supplied on deploy/init so cloud and self-hosted deployments can use the same config-driven model. Built-in profiles are general, literary, medical, legal, and saas. They use the same config shape as custom ontologies and include lightweight references to mature vocabularies such as Schema.org, Wikidata, HL7 FHIR, SNOMED CT, LOINC, RxNorm, ELI, Akoma Ntoso, LegalRuleML, OpenTelemetry semantic conventions, TM Forum SID, and ITIL. These references are metadata for grounding, mapping, and future import tooling; they are not expanded into the extraction prompt.

Memory

Memory operations share the same context and optional graphExtraction shape. Structured memory records remain the recall layer:

await tg.memory.remember('Dana prefers concise renewal risk summaries.', {
  context: {
    userId: UserId('dana'),
  },
  graphExtraction: true,
})

await tg.memory.correct('Dana no longer owns Acme renewals; Taylor does.', {
  context: {
    userId: UserId('taylor'),
  },
  graphExtraction: true,
})

const recalled = await tg.memory.recall('renewal summary style', {
  context: { userId: UserId('dana') },
  types: ['semantic'],
  limit: 5,
})

Conversation memory adds database-backed Markdown-like artifacts for agent context. Thread turns are stored as linked events, then extractThread() writes raw memory and rollout summary artifacts. consolidate() rewrites the durable handbook and compact prompt summary. context() returns the progressive read path: summary first, relevant handbook blocks, and optional structured recall.

await tg.thread.addTurn('thread_123', {
  role: 'user',
  content: 'Keep implementation plans concise and decision complete.',
}, {
  context: {
    userId: UserId('dana'),
    threadId: 'thread_123',
  },
})

await tg.memory.extractThread('thread_123', {
  context: { userId: UserId('dana') },
})

await tg.memory.consolidate({
  context: { userId: UserId('dana') },
})

const contextMemory = await tg.memory.context('planning style', {
  context: { userId: UserId('dana') },
  includeStructuredRecall: true,
  format: 'markdown',
})

console.log(contextMemory.prompt)

Artifact paths follow the default layout:

  • memory_summary.md
  • MEMORY.md
  • raw_memories.md
  • raw_memories/<thread-id>.md
  • rollout_summaries/<thread-id>_<slug>.md
  • phase_two_selection.json
  • skills/<skill-name>/SKILL.md

Direct artifact access is available when you need to inspect or manage the database-backed files explicitly:

await tg.memory.artifacts.upsert({
  path: 'MEMORY.md',
  kind: 'handbook',
  content: '# Task Group: Planning\n\nscope: Use for implementation plans.\n',
}, {
  context: { userId: UserId('dana') },
})

const summary = await tg.memory.artifacts.get('memory_summary.md', {
  context: { userId: UserId('dana') },
})

const raw = await tg.memory.artifacts.list({
  context: { userId: UserId('dana') },
  prefix: 'raw_memories',
})

Cloud clients expose the same typed memory surface. Self-hosted apps need an adapter with memory artifact persistence, such as @typegraph-ai/adapter-pgvector, and an llm for extraction and consolidation.

Main Exports

| Export | Purpose | | --- | --- | | typegraphInit | Initialize a TypeGraph runtime instance | | typegraphDeploy | Create required storage objects for self-hosted mode | | TenantId, UserId, GroupId, AgentId, ThreadId, EntityId, entityRef | Branded identity helpers | | aiSdkEmbedder, aiSdkLlmProvider | Explicit AI SDK wrappers when needed | | Embedder, Extractor, Reranker, OntologyConfig | Pluggable model/extraction contracts | | SearchOptions, SearchResource, SearchWeights, QueryResponse, PromptBuilderOptions | Search and prompt assembly types | | DocumentInput, EventInput, ThreadInput, ThreadTurnInput | Primary write model types | | MemoryArtifact, MemoryArtifactKind, ConversationMemoryExtraction, MemoryContextResult | Memory artifact and conversation memory types |

Learn More