npm package: @kbforge/sdk
Description: TypeScript SDK for the KBForge API — semantic search and RAG chat over your knowledge bases
Latest version: 0.1.1

# @kbforge/sdk

TypeScript SDK for the [KBForge](https://kbforge.app) API — semantic search and RAG chat over your knowledge bases.

## Installation

```bash
npm install @kbforge/sdk
```

## Quick Start

```typescript
import { KBForge } from "@kbforge/sdk";

const kb = new KBForge({ apiKey: "kbf_..." });

// Semantic search
const results = await kb.retrieve({
  query: "how to configure OAuth",
  knowledgeBase: "my-docs",
});

// RAG chat (streaming)
for await (const event of await kb.chat({
  knowledgeBase: "my-docs",
  messages: [{ role: "user", content: "How does auth work?" }],
})) {
  process.stdout.write(event.content);
}

// RAG chat (full text)
const answer = await kb.chatText({
  knowledgeBase: "my-docs",
  messages: [{ role: "user", content: "Summarize the docs" }],
});
```

## Authentication

All API calls require an API key. Create one from the KBForge dashboard under **Settings > API Keys**.

```typescript
const kb = new KBForge({
  apiKey: "kbf_...",
  baseUrl: "https://kbforge.app", // optional, defaults to https://kbforge.app
});
```

### API Key Permissions

Each API key can be configured with granular permissions:

| Permission | Access |
|-----------|--------|
| `retrieve` | Semantic search and RAG chat |
| `ingest` | Upload and process documents |
| `manage` | CRUD on knowledge bases, documents, tags, segments |
| `chunks` | Edit, split, merge, pin, boost chunks |
| `admin` | Analytics and settings |

API keys can also be **scoped to a specific knowledge base**, restricting all operations to that KB only.

## API Reference

### Retrieve

Search your knowledge base using semantic similarity.

```typescript
const results = await kb.retrieve({
  query: "how to deploy",        // required
  knowledgeBase: "my-docs",      // required — KB id or slug
  limit: 5,                      // optional, default 5
  threshold: 0.3,                // optional, min similarity score (0-1)
  segment: "getting-started",    // optional — segment id or name
  tag: "deployment",             // optional — tag id or name
});

// results.chunks[0].content     — matched text
// results.chunks[0].score       — similarity score
// results.chunks[0].documentTitle
// results.chunks[0].chunkId
// results.latencyMs
```

### Chat

RAG-powered chat with streaming responses. Automatically retrieves relevant context from your knowledge base.

```typescript
// Streaming
const stream = await kb.chat({
  knowledgeBase: "my-docs",      // required
  messages: [                    // required
    { role: "user", content: "What is KBForge?" },
  ],
  systemPrompt: "Be concise.",  // optional — override default prompt
  segment: "faq",               // optional
  tag: "general",               // optional
});

for await (const event of stream) {
  process.stdout.write(event.content);
}

// Or get the full response at once
const answer = await kb.chatText({
  knowledgeBase: "my-docs",
  messages: [{ role: "user", content: "What is KBForge?" }],
});
console.log(answer);
```

### Knowledge Bases

**Permission required:** `manage`

```typescript
// List all knowledge bases
const { knowledgeBases } = await kb.knowledgeBases.list();

// Create a knowledge base
const newKB = await kb.knowledgeBases.create({
  name: "Product Docs",
  description: "Internal product documentation",
});

// Delete a knowledge base
await kb.knowledgeBases.delete("kb-id");
```

### Documents

**Permission required:** `ingest` (upload), `manage` (list, delete)

```typescript
// List documents in a knowledge base
const { documents, total } = await kb.documents.list("kb-id");

// Upload a file
const file = new File(["content"], "guide.pdf", { type: "application/pdf" });
const doc = await kb.documents.upload({
  knowledgeBaseId: "kb-id",
  file: file,
});
// doc.status === "pending" — processing starts automatically

// Upload plain text
const textDoc = await kb.documents.uploadText({
  knowledgeBaseId: "kb-id",
  title: "Quick Start Guide",
  content: "# Getting Started\n\nWelcome to...",
});

// Delete a document
await kb.documents.delete("doc-id");
```

### Chunks

**Permission required:** `chunks`

```typescript
// List chunks for a document
const { chunks, total } = await kb.chunks.list("doc-id");
const activeOnly = await kb.chunks.list("doc-id", { activeOnly: true });

// Get a single chunk
const chunk = await kb.chunks.get("chunk-id");

// Create a manual chunk
const newChunk = await kb.chunks.create({
  documentId: "doc-id",
  knowledgeBaseId: "kb-id",
  content: "This is a new chunk of text.",
  insertAfterIndex: 2,  // optional — position to insert at
});

// Update a chunk
await kb.chunks.update("chunk-id", {
  content: "Updated text",     // triggers re-embedding
  pinned: true,                // pin to boost in search
  boost: 1.5,                  // relevance multiplier (0.1 - 3.0)
  isActive: true,              // activate/deactivate
});

// Delete a chunk
await kb.chunks.delete("chunk-id");

// Split a chunk at a character position
const splitResult = await kb.chunks.split("chunk-id", 150);
// splitResult.chunks — array of 2 new chunks

// Merge adjacent chunks
const mergeResult = await kb.chunks.merge(["chunk-id-1", "chunk-id-2"]);
// mergeResult.chunk — the merged chunk

// Bulk operations
await kb.chunks.bulk({
  action: "pin",  // "activate" | "deactivate" | "pin" | "unpin" | "boost" | "delete"
  chunkIds: ["chunk-1", "chunk-2", "chunk-3"],
  boostValue: 2.0,  // only used with action: "boost"
});
```

### Tags

**Permission required:** `manage`

```typescript
// List tags in a knowledge base
const { tags } = await kb.tags.list("kb-id");

// Create a tag
const tag = await kb.tags.create({
  knowledgeBaseId: "kb-id",
  name: "deployment",
  description: "Deployment-related docs",
  color: "#3B82F6",
});

// Update a tag
await kb.tags.update("tag-id", { name: "deploy", color: "#10B981" });

// Delete a tag
await kb.tags.delete("tag-id");

// Assign documents to a tag
await kb.tags.addDocuments("tag-id", ["doc-id-1", "doc-id-2"]);

// Remove a document from a tag
await kb.tags.removeDocument("tag-id", "doc-id");
```

### Segments

**Permission required:** `manage`

Segments work exactly like tags — they group documents for filtered search.

```typescript
// List segments
const { segments } = await kb.segments.list("kb-id");

// Create a segment
const segment = await kb.segments.create({
  knowledgeBaseId: "kb-id",
  name: "Getting Started",
  description: "Onboarding docs",
  color: "#8B5CF6",
});

// Update / Delete
await kb.segments.update("segment-id", { name: "Onboarding" });
await kb.segments.delete("segment-id");

// Assign / Remove documents
await kb.segments.addDocuments("segment-id", ["doc-id-1", "doc-id-2"]);
await kb.segments.removeDocument("segment-id", "doc-id");
```

### Analytics

**Permission required:** `admin`

```typescript
// Overview stats
const overview = await kb.analytics.overview("kb-id");
// overview.totalQueries, .queriesToday, .queriesThisWeek
// overview.avgLatencyMs, .avgResultCount, .avgTopScore

// Queries per day (last 30 days)
const { data: daily } = await kb.analytics.queriesPerDay("kb-id", 30);
// daily[0] = { date: "2026-03-01", count: 42 }

// Top queries
const { data: topQueries } = await kb.analytics.topQueries("kb-id", 10);
// topQueries[0] = { queryText: "how to deploy", count: 15, avgScore: 0.82 }

// Most retrieved documents
const { data: topDocs } = await kb.analytics.topDocuments("kb-id", 10);
// topDocs[0] = { documentId: "...", documentTitle: "Deploy Guide", hitCount: 30 }

// Gap analysis (low-scoring queries)
const { data: gaps } = await kb.analytics.gaps("kb-id", 10);
// gaps[0] = { queryText: "pricing info", count: 5, avgScore: 0.12, lastSeen: "..." }
```

## Error Handling

All methods throw `KBForgeError` on failure:

```typescript
import { KBForge, KBForgeError } from "@kbforge/sdk";

try {
  await kb.retrieve({ query: "test", knowledgeBase: "nonexistent" });
} catch (err) {
  if (err instanceof KBForgeError) {
    console.error(err.message);  // "Knowledge base not found"
    console.error(err.status);   // 404
  }
}
```

### Common error codes

| Status | Meaning |
|--------|---------|
| 400 | Invalid request (missing fields, bad input) |
| 401 | Invalid, revoked, or expired API key |
| 403 | Missing permission or KB scope mismatch |
| 404 | Resource not found |
| 409 | Conflict (duplicate name) |
| 429 | Monthly retrieval limit exceeded |
| 500 | Internal server error |

## TypeScript

All types are exported:

```typescript
import type {
  RetrieveOptions,
  RetrieveResponse,
  RetrieveChunk,
  ChatMessage,
  ChatOptions,
  KnowledgeBase,
  Document,
  Chunk,
  Tag,
  Segment,
  AnalyticsOverview,
  // ... and more
} from "@kbforge/sdk";
```

## Requirements

- Node.js 18+ (uses native `fetch`)
- Works in browsers, Deno, Bun, and Cloudflare Workers

## License

MIT