@kbforge/sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +347 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# @kbforge/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the [KBForge](https://kbforge.app) API — semantic search and RAG chat over your knowledge bases.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @kbforge/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { KBForge } from "@kbforge/sdk";
|
|
15
|
+
|
|
16
|
+
const kb = new KBForge({ apiKey: "kbf_..." });
|
|
17
|
+
|
|
18
|
+
// Semantic search
|
|
19
|
+
const results = await kb.retrieve({
|
|
20
|
+
query: "how to configure OAuth",
|
|
21
|
+
knowledgeBase: "my-docs",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// RAG chat (streaming)
|
|
25
|
+
for await (const event of await kb.chat({
|
|
26
|
+
knowledgeBase: "my-docs",
|
|
27
|
+
messages: [{ role: "user", content: "How does auth work?" }],
|
|
28
|
+
})) {
|
|
29
|
+
process.stdout.write(event.content);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// RAG chat (full text)
|
|
33
|
+
const answer = await kb.chatText({
|
|
34
|
+
knowledgeBase: "my-docs",
|
|
35
|
+
messages: [{ role: "user", content: "Summarize the docs" }],
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Authentication
|
|
40
|
+
|
|
41
|
+
All API calls require an API key. Create one from the KBForge dashboard under **Settings > API Keys**.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const kb = new KBForge({
|
|
45
|
+
apiKey: "kbf_...",
|
|
46
|
+
baseUrl: "https://kbforge.app", // optional, defaults to https://kbforge.app
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### API Key Permissions
|
|
51
|
+
|
|
52
|
+
Each API key can be configured with granular permissions:
|
|
53
|
+
|
|
54
|
+
| Permission | Access |
|
|
55
|
+
|-----------|--------|
|
|
56
|
+
| `retrieve` | Semantic search and RAG chat |
|
|
57
|
+
| `ingest` | Upload and process documents |
|
|
58
|
+
| `manage` | CRUD on knowledge bases, documents, tags, segments |
|
|
59
|
+
| `chunks` | Edit, split, merge, pin, boost chunks |
|
|
60
|
+
| `admin` | Analytics and settings |
|
|
61
|
+
|
|
62
|
+
API keys can also be **scoped to a specific knowledge base**, restricting all operations to that KB only.
|
|
63
|
+
|
|
64
|
+
## API Reference
|
|
65
|
+
|
|
66
|
+
### Retrieve
|
|
67
|
+
|
|
68
|
+
Search your knowledge base using semantic similarity.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const results = await kb.retrieve({
|
|
72
|
+
query: "how to deploy", // required
|
|
73
|
+
knowledgeBase: "my-docs", // required — KB id or slug
|
|
74
|
+
limit: 5, // optional, default 5
|
|
75
|
+
threshold: 0.3, // optional, min similarity score (0-1)
|
|
76
|
+
segment: "getting-started", // optional — segment id or name
|
|
77
|
+
tag: "deployment", // optional — tag id or name
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// results.chunks[0].content — matched text
|
|
81
|
+
// results.chunks[0].score — similarity score
|
|
82
|
+
// results.chunks[0].documentTitle
|
|
83
|
+
// results.chunks[0].chunkId
|
|
84
|
+
// results.latencyMs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Chat
|
|
88
|
+
|
|
89
|
+
RAG-powered chat with streaming responses. Automatically retrieves relevant context from your knowledge base.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Streaming
|
|
93
|
+
const stream = await kb.chat({
|
|
94
|
+
knowledgeBase: "my-docs", // required
|
|
95
|
+
messages: [ // required
|
|
96
|
+
{ role: "user", content: "What is KBForge?" },
|
|
97
|
+
],
|
|
98
|
+
systemPrompt: "Be concise.", // optional — override default prompt
|
|
99
|
+
segment: "faq", // optional
|
|
100
|
+
tag: "general", // optional
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
for await (const event of stream) {
|
|
104
|
+
process.stdout.write(event.content);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Or get the full response at once
|
|
108
|
+
const answer = await kb.chatText({
|
|
109
|
+
knowledgeBase: "my-docs",
|
|
110
|
+
messages: [{ role: "user", content: "What is KBForge?" }],
|
|
111
|
+
});
|
|
112
|
+
console.log(answer);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Knowledge Bases
|
|
116
|
+
|
|
117
|
+
**Permission required:** `manage`
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// List all knowledge bases
|
|
121
|
+
const { knowledgeBases } = await kb.knowledgeBases.list();
|
|
122
|
+
|
|
123
|
+
// Create a knowledge base
|
|
124
|
+
const newKB = await kb.knowledgeBases.create({
|
|
125
|
+
name: "Product Docs",
|
|
126
|
+
description: "Internal product documentation",
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Delete a knowledge base
|
|
130
|
+
await kb.knowledgeBases.delete("kb-id");
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Documents
|
|
134
|
+
|
|
135
|
+
**Permission required:** `ingest` (upload), `manage` (list, delete)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// List documents in a knowledge base
|
|
139
|
+
const { documents, total } = await kb.documents.list("kb-id");
|
|
140
|
+
|
|
141
|
+
// Upload a file
|
|
142
|
+
const file = new File(["content"], "guide.pdf", { type: "application/pdf" });
|
|
143
|
+
const doc = await kb.documents.upload({
|
|
144
|
+
knowledgeBaseId: "kb-id",
|
|
145
|
+
file: file,
|
|
146
|
+
});
|
|
147
|
+
// doc.status === "pending" — processing starts automatically
|
|
148
|
+
|
|
149
|
+
// Upload plain text
|
|
150
|
+
const textDoc = await kb.documents.uploadText({
|
|
151
|
+
knowledgeBaseId: "kb-id",
|
|
152
|
+
title: "Quick Start Guide",
|
|
153
|
+
content: "# Getting Started\n\nWelcome to...",
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Delete a document
|
|
157
|
+
await kb.documents.delete("doc-id");
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Chunks
|
|
161
|
+
|
|
162
|
+
**Permission required:** `chunks`
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// List chunks for a document
|
|
166
|
+
const { chunks, total } = await kb.chunks.list("doc-id");
|
|
167
|
+
const activeOnly = await kb.chunks.list("doc-id", { activeOnly: true });
|
|
168
|
+
|
|
169
|
+
// Get a single chunk
|
|
170
|
+
const chunk = await kb.chunks.get("chunk-id");
|
|
171
|
+
|
|
172
|
+
// Create a manual chunk
|
|
173
|
+
const newChunk = await kb.chunks.create({
|
|
174
|
+
documentId: "doc-id",
|
|
175
|
+
knowledgeBaseId: "kb-id",
|
|
176
|
+
content: "This is a new chunk of text.",
|
|
177
|
+
insertAfterIndex: 2, // optional — position to insert at
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Update a chunk
|
|
181
|
+
await kb.chunks.update("chunk-id", {
|
|
182
|
+
content: "Updated text", // triggers re-embedding
|
|
183
|
+
pinned: true, // pin to boost in search
|
|
184
|
+
boost: 1.5, // relevance multiplier (0.1 - 3.0)
|
|
185
|
+
isActive: true, // activate/deactivate
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Delete a chunk
|
|
189
|
+
await kb.chunks.delete("chunk-id");
|
|
190
|
+
|
|
191
|
+
// Split a chunk at a character position
|
|
192
|
+
const splitResult = await kb.chunks.split("chunk-id", 150);
|
|
193
|
+
// splitResult.chunks — array of 2 new chunks
|
|
194
|
+
|
|
195
|
+
// Merge adjacent chunks
|
|
196
|
+
const mergeResult = await kb.chunks.merge(["chunk-id-1", "chunk-id-2"]);
|
|
197
|
+
// mergeResult.chunk — the merged chunk
|
|
198
|
+
|
|
199
|
+
// Bulk operations
|
|
200
|
+
await kb.chunks.bulk({
|
|
201
|
+
action: "pin", // "activate" | "deactivate" | "pin" | "unpin" | "boost" | "delete"
|
|
202
|
+
chunkIds: ["chunk-1", "chunk-2", "chunk-3"],
|
|
203
|
+
boostValue: 2.0, // only used with action: "boost"
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Tags
|
|
208
|
+
|
|
209
|
+
**Permission required:** `manage`
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// List tags in a knowledge base
|
|
213
|
+
const { tags } = await kb.tags.list("kb-id");
|
|
214
|
+
|
|
215
|
+
// Create a tag
|
|
216
|
+
const tag = await kb.tags.create({
|
|
217
|
+
knowledgeBaseId: "kb-id",
|
|
218
|
+
name: "deployment",
|
|
219
|
+
description: "Deployment-related docs",
|
|
220
|
+
color: "#3B82F6",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Update a tag
|
|
224
|
+
await kb.tags.update("tag-id", { name: "deploy", color: "#10B981" });
|
|
225
|
+
|
|
226
|
+
// Delete a tag
|
|
227
|
+
await kb.tags.delete("tag-id");
|
|
228
|
+
|
|
229
|
+
// Assign documents to a tag
|
|
230
|
+
await kb.tags.addDocuments("tag-id", ["doc-id-1", "doc-id-2"]);
|
|
231
|
+
|
|
232
|
+
// Remove a document from a tag
|
|
233
|
+
await kb.tags.removeDocument("tag-id", "doc-id");
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Segments
|
|
237
|
+
|
|
238
|
+
**Permission required:** `manage`
|
|
239
|
+
|
|
240
|
+
Segments work exactly like tags — they group documents for filtered search.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// List segments
|
|
244
|
+
const { segments } = await kb.segments.list("kb-id");
|
|
245
|
+
|
|
246
|
+
// Create a segment
|
|
247
|
+
const segment = await kb.segments.create({
|
|
248
|
+
knowledgeBaseId: "kb-id",
|
|
249
|
+
name: "Getting Started",
|
|
250
|
+
description: "Onboarding docs",
|
|
251
|
+
color: "#8B5CF6",
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Update / Delete
|
|
255
|
+
await kb.segments.update("segment-id", { name: "Onboarding" });
|
|
256
|
+
await kb.segments.delete("segment-id");
|
|
257
|
+
|
|
258
|
+
// Assign / Remove documents
|
|
259
|
+
await kb.segments.addDocuments("segment-id", ["doc-id-1", "doc-id-2"]);
|
|
260
|
+
await kb.segments.removeDocument("segment-id", "doc-id");
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Analytics
|
|
264
|
+
|
|
265
|
+
**Permission required:** `admin`
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// Overview stats
|
|
269
|
+
const overview = await kb.analytics.overview("kb-id");
|
|
270
|
+
// overview.totalQueries, .queriesToday, .queriesThisWeek
|
|
271
|
+
// overview.avgLatencyMs, .avgResultCount, .avgTopScore
|
|
272
|
+
|
|
273
|
+
// Queries per day (last 30 days)
|
|
274
|
+
const { data: daily } = await kb.analytics.queriesPerDay("kb-id", 30);
|
|
275
|
+
// daily[0] = { date: "2026-03-01", count: 42 }
|
|
276
|
+
|
|
277
|
+
// Top queries
|
|
278
|
+
const { data: topQueries } = await kb.analytics.topQueries("kb-id", 10);
|
|
279
|
+
// topQueries[0] = { queryText: "how to deploy", count: 15, avgScore: 0.82 }
|
|
280
|
+
|
|
281
|
+
// Most retrieved documents
|
|
282
|
+
const { data: topDocs } = await kb.analytics.topDocuments("kb-id", 10);
|
|
283
|
+
// topDocs[0] = { documentId: "...", documentTitle: "Deploy Guide", hitCount: 30 }
|
|
284
|
+
|
|
285
|
+
// Gap analysis (low-scoring queries)
|
|
286
|
+
const { data: gaps } = await kb.analytics.gaps("kb-id", 10);
|
|
287
|
+
// gaps[0] = { queryText: "pricing info", count: 5, avgScore: 0.12, lastSeen: "..." }
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Error Handling
|
|
291
|
+
|
|
292
|
+
All methods throw `KBForgeError` on failure:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { KBForge, KBForgeError } from "@kbforge/sdk";
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
await kb.retrieve({ query: "test", knowledgeBase: "nonexistent" });
|
|
299
|
+
} catch (err) {
|
|
300
|
+
if (err instanceof KBForgeError) {
|
|
301
|
+
console.error(err.message); // "Knowledge base not found"
|
|
302
|
+
console.error(err.status); // 404
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Common error codes
|
|
308
|
+
|
|
309
|
+
| Status | Meaning |
|
|
310
|
+
|--------|---------|
|
|
311
|
+
| 400 | Invalid request (missing fields, bad input) |
|
|
312
|
+
| 401 | Invalid, revoked, or expired API key |
|
|
313
|
+
| 403 | Missing permission or KB scope mismatch |
|
|
314
|
+
| 404 | Resource not found |
|
|
315
|
+
| 409 | Conflict (duplicate name) |
|
|
316
|
+
| 429 | Monthly retrieval limit exceeded |
|
|
317
|
+
| 500 | Internal server error |
|
|
318
|
+
|
|
319
|
+
## TypeScript
|
|
320
|
+
|
|
321
|
+
All types are exported:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
import type {
|
|
325
|
+
RetrieveOptions,
|
|
326
|
+
RetrieveResponse,
|
|
327
|
+
RetrieveChunk,
|
|
328
|
+
ChatMessage,
|
|
329
|
+
ChatOptions,
|
|
330
|
+
KnowledgeBase,
|
|
331
|
+
Document,
|
|
332
|
+
Chunk,
|
|
333
|
+
Tag,
|
|
334
|
+
Segment,
|
|
335
|
+
AnalyticsOverview,
|
|
336
|
+
// ... and more
|
|
337
|
+
} from "@kbforge/sdk";
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Requirements
|
|
341
|
+
|
|
342
|
+
- Node.js 18+ (uses native `fetch`)
|
|
343
|
+
- Works in browsers, Deno, Bun, and Cloudflare Workers
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT
|