TypeGraph gives AI apps a typed layer for business context: buckets, documents, events, threads, entities, facts, memory, search, jobs, policies, ontology, and telemetry. It runs against TypeGraph Cloud or self-hosted Postgres with pgvector.
This branch reflects the current breaking SDK shape. The old source and
query surfaces have been replaced by document and search, tenantId is
client-scoped, per-call actor identity lives under context, graph access lives
on graph config, and SQLite vector
storage is no longer supported.
For deeper guides and production patterns, use the docs: typegraph.ai/docs.
Cloud projects usually need only the SDK:
pnpm add @typegraph-ai/sdkSelf-hosted projects need the SDK, the pgvector adapter, a Postgres client, and the AI provider package used by your app:
pnpm add @typegraph-ai/sdk @typegraph-ai/adapter-pgvector @ai-sdk/gateway @neondatabase/serverlessCloud mode runs storage, embedding, indexing, graph, and memory server-side.
tenantId defaults to public; pass a tenant only when you need separate
customer/account graphs.
import { typegraphInit, GroupId, UserId } 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('employees')] },
write: { groups: [GroupId('employees')] },
},
},
},
buckets: {
public: { graph: 'public' },
handbook: { name: 'Employee Handbook', graph: 'internal', graphExtraction: true },
},
})
await tg.document.ingest(
{
id: 'handbook:sso',
name: 'Employee handbook',
description: 'Internal handbook section for SSO setup.',
content: 'Acme employees configure SSO from the admin security page.',
metadata: { system: 'notion' },
},
{
context: {
userId: UserId('dana'),
groupId: GroupId('employees'),
},
bucketId: 'handbook',
},
)
const response = await tg.search('How do employees configure SSO?', {
graph: 'internal',
context: {
userId: UserId('dana'),
groupId: GroupId('employees'),
},
resources: ['documents', 'facts', 'entities'],
weights: { semantic: 1, bm25: 0.7, graph: 0.5, recency: 0.3 },
promptBuilder: {
format: 'xml',
sections: ['chunks', 'facts', 'entities'],
maxTotalTokens: 4000,
},
})
console.log(response.prompt)Self-hosted mode uses the same runtime API, but you provide storage, embedding,
and LLM configuration. vectorStore + embedding + llm is enough to enable
document ingest, search, graph extraction, graph APIs, and memory APIs when the
adapter supports those capabilities.
import { gateway } from '@ai-sdk/gateway'
import { neon } from '@neondatabase/serverless'
import { PgVectorAdapter } from '@typegraph-ai/adapter-pgvector'
import { typegraphDeploy, typegraphInit } from '@typegraph-ai/sdk'
const sql = neon(process.env.DATABASE_URL!)
const vectorStore = new PgVectorAdapter({ sql })
const config = {
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'),
},
ontology: {
version: '2026-05-08',
profiles: ['saas'],
entities: {
organization: {
description: 'A company, customer, vendor, or partner.',
vocabulary: [{ vocabulary: 'schema.org', id: 'Organization', uri: 'https://schema.org/Organization' }],
},
person: { description: 'A human user, employee, or contact.' },
system: { description: 'A software system or business application.' },
},
relations: {
USES: { from: ['organization'], to: ['system'] },
OWNS: { from: ['organization', 'person'], to: ['system'] },
WORKS_WITH: { from: ['person'], to: ['organization', 'person'] },
},
},
}
await typegraphDeploy(config)
const tg = await typegraphInit(config)typegraphDeploy(config) provisions storage and is intended for deploy scripts.
typegraphInit(config) is the lightweight runtime initializer for app boot.
Self-hosted users do not need to call bridge constructors.
Primary records use the same naming shape where applicable:
{
id: string
name: string
description?: string
metadata?: Record<string, unknown>
}The main public namespaces are:
| Namespace | Purpose |
|---|---|
tg.bucket |
Named containers for documents and events. Search accepts bucket ids or bucket names. |
tg.document |
Durable long-form content with chunks and embeddings. |
tg.event |
Time-anchored business occurrences with participants and attached documents. |
tg.thread |
Ordered containers; turns are stored as linked events. |
tg.search |
Unified retrieval over selected resources. |
tg.graph |
Entity, fact, edge, external ID, merge, explore, and graph search APIs. |
tg.memory |
Private memory operations: remember, recall, correct, forget, healthCheck. |
tg.job |
Job tracking primitives. |
tg.policy |
Governance policy CRUD when a policy store is configured. |
tenantId is configured once on typegraphInit() or typegraphDeploy().
Per-call actor identity uses one optional key: context.
import {
AgentId,
GroupId,
OrganizationId,
ThreadId,
UserId,
type TypeGraphContext,
} from '@typegraph-ai/sdk'
const context: TypeGraphContext = {
organizationId: OrganizationId('org_acme'),
groupId: GroupId('product'),
userId: UserId('dana'),
agentId: AgentId('product-ops-agent'),
threadId: ThreadId('thread_123'),
}Graphs are the logical knowledge boundaries inside a tenant. Reads from graph
internal include internal plus its ancestors, such as public. Parent
graphs never read child graph data.
Buckets own write routing. If no bucket is supplied, writes use bucket public,
which writes to graph public. Event participants, entities, and facts model
business relationships; they do not grant access.
Documents are the primary long-form ingest target. A raw transcript often has a narrower audience than the product signal extracted from it:
await tg.document.ingest(
{
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' },
},
{
context: {
userId: UserId('dana'),
groupId: GroupId('success'),
},
bucketId: 'gong',
idempotencyKey: 'gong:transcript:123',
},
)Events model business activity. This event is a product signal from the Acme
call. The participants create the business shape for graph extraction and
exploration; the gong bucket routes the write into the internal graph.
await tg.event.ingest(
{
id: 'gong:meeting:123:signal:sso-redirect-loop',
name: 'Acme reports SSO redirect loop',
description: 'Acme is blocked by a SAML redirect loop during SSO rollout.',
url: 'https://gong.example.com/calls/123',
occurredAt: new Date(),
participants: [
entityRef('organization', 'org_acme'),
entityRef('product_area', 'auth'),
entityRef('issue', 'sso_redirect_loop'),
],
content: 'Acme reports that SAML login loops after the IdP callback. This is blocking enterprise rollout.',
metadata: { provider: 'gong', meetingId: '123', severity: 'high' },
},
{
context: {
userId: UserId('dana'),
groupId: GroupId('success'),
},
bucketId: 'gong',
},
)That supports cross-customer questions:
const response = await tg.search('Which customers are experiencing SSO redirect loops?', {
graph: 'internal',
context: { groupId: GroupId('product') },
resources: ['events', 'facts', 'entities'],
weights: { semantic: 1, bm25: 0.5, graph: 0.9, recency: 0.4 },
promptBuilder: { format: 'markdown', sections: ['facts', 'entities'] },
})If a customer portal user should see only public knowledge, search graph
public. Internal teams can search graph internal, which includes public
knowledge plus internal customer activity.
Threads are ordered containers. thread.addTurn() stores the turn as an event
and links the event back to the thread. A turn has only role, content, URL,
timestamp, and metadata.
await tg.thread.addTurn(
'thread_support_123',
{
role: 'user',
content: 'Can you send the SOC2 report?',
url: 'https://slack.example.com/archives/C123/p456',
timestamp: new Date(),
metadata: { channel: 'slack' },
},
{
context: {
userId: UserId('dana'),
threadId: ThreadId('thread_support_123'),
groupId: GroupId('support'),
},
bucketId: 'gong',
},
)document.ingest() and event.ingest() accept a single input or an array.
abortSignal is available on write and search options for cancellation.
tg.search() separates target selection from retrieval scoring.
resources selects what to search:
type SearchResource =
| 'documents'
| 'events'
| 'threads'
| 'entities'
| 'facts'weights controls how candidates are scored and fused:
| Weight | Purpose | Default |
|---|---|---|
semantic |
Embedding search over content-bearing records | 1 |
bm25 |
Keyword/BM25 search fused with semantic results | 0.7 |
graph |
Graph-aware facts, entities, and chunk expansion | 0.5 |
recency |
Prefer fresher records in final scoring | 0.3 |
Set a weight to false to disable that signal.
const response = await tg.search('How are Alice and Acme related?', {
context: { userId: UserId('dana') },
buckets: ['salesforce', 'slack'],
resources: ['documents', 'events', 'facts', 'entities'],
weights: { semantic: 1, bm25: 0.7, graph: 0.8, recency: 0.2 },
fusion: { method: 'rrf', k: 60 },
rerank: { topK: 20, domain: 'general' },
explain: true,
promptBuilder: {
format: 'markdown',
sections: ['chunks', 'facts', 'entities'],
includeAttributes: false,
maxTotalTokens: 6000,
},
})
response.results.chunks
response.results.facts
response.results.entities
response.explanation
response.promptHits expose output scores, not input weights:
hit.scores.output
// {
// semantic?: number
// bm25?: number
// graph?: number
// recency?: number
// fused: number
// reranker?: number
// }TypeGraph uses final Embedder naming:
type Embedder = {
name: string
dimensions: number
maxBatchSize?: number
supportsAsymmetric?: boolean
embed(input: {
texts: string[]
inputType?: 'document' | 'search'
outputDimensions?: number
abortSignal?: AbortSignal
}): Promise<number[][]>
}Ingest uses embedding; search uses searchEmbedding when supplied. Bucket
configuration uses embeddingModel and searchEmbeddingModel.
Graph extraction runs the configured extractor. If you pass llm, TypeGraph
builds its default extractor. If you pass extractor, your extractor wins.
Single-pass vs. multi-pass prompting is private implementation detail.
const config = {
vectorStore,
embedding,
searchEmbedding,
llm,
extractor, // optional custom extractor
ontology: {
version: '2026-05-08',
profiles: ['general'], // built-ins: general, literary, medical, legal, saas
// optional custom entity/relation definitions use the same shape as profiles
},
}Applications can seed business entities and facts directly instead of relying only on extraction:
await tg.graph.upsertEntity(
{
id: 'org_acme',
name: 'Acme Corp',
entityType: 'organization',
description: 'Customer account for Acme Corp.',
externalIds: [{ type: 'salesforce_account_id', id: '001xx000003DGSW' }],
},
{
context: {
userId: UserId('dana'),
groupId: GroupId('product'),
},
},
)
await tg.graph.upsertFact(
{
source: { id: 'org_acme' },
relation: 'USES',
target: { name: 'Salesforce', entityType: 'system' },
description: 'Acme Corp uses Salesforce as its CRM.',
},
{
context: {
userId: UserId('dana'),
groupId: GroupId('product'),
},
},
)Facts use description as their assertion and search text.
| Package | Purpose |
|---|---|
@typegraph-ai/sdk |
Main SDK: initialization, documents, events, threads, search, graph, memory, jobs, policies, and types. |
@typegraph-ai/adapter-pgvector |
Core Postgres + pgvector adapter and memory/graph backing store. |
@typegraph-ai/adapter-pgvector-neon |
Neon convenience adapter. |
@typegraph-ai/adapter-pgvector-pg |
node-postgres convenience adapter. |
@typegraph-ai/adapter-pgvector-supabase |
Supabase/Postgres convenience adapter. |
@typegraph-ai/adapter-pgvector-rds |
AWS RDS/Postgres convenience adapter. |
@typegraph-ai/adapter-pgvector-nile |
Nile/Postgres convenience adapter. |
@typegraph-ai/adapter-pgvector-prisma |
Prisma convenience adapter. |
@typegraph-ai/adapter-redis |
Redis-backed extraction coreference cache for self-hosted deployments. |
@typegraph-ai/adapter-redis-upstash |
Upstash Redis coreference cache adapter for self-hosted deployments. |
@typegraph-ai/vercel-ai-provider |
Vercel AI SDK tools and middleware. |
@typegraph-ai/mcp-server |
MCP server package. |
@typegraph-ai/otel |
OpenTelemetry event sink integration. |
pnpm install
pnpm build
pnpm test
pnpm typecheckFocused SDK checks:
pnpm --filter @typegraph-ai/sdk test
pnpm --filter @typegraph-ai/sdk typecheck