@backendkit-labs/agent-enterprise 0.3.0 → 0.3.2
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 +446 -111
- package/dist/factory.d.ts +47 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +146 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/profiles/constants.d.ts +22 -0
- package/dist/profiles/constants.d.ts.map +1 -0
- package/dist/profiles/constants.js +25 -0
- package/dist/profiles/constants.js.map +1 -0
- package/dist/profiles/finance.d.ts +3 -0
- package/dist/profiles/finance.d.ts.map +1 -0
- package/dist/profiles/finance.js +34 -0
- package/dist/profiles/finance.js.map +1 -0
- package/dist/profiles/general.d.ts +3 -0
- package/dist/profiles/general.d.ts.map +1 -0
- package/dist/profiles/general.js +32 -0
- package/dist/profiles/general.js.map +1 -0
- package/dist/profiles/hr.d.ts +3 -0
- package/dist/profiles/hr.d.ts.map +1 -0
- package/dist/profiles/hr.js +34 -0
- package/dist/profiles/hr.js.map +1 -0
- package/dist/profiles/index.d.ts +10 -0
- package/dist/profiles/index.d.ts.map +1 -0
- package/dist/profiles/index.js +33 -0
- package/dist/profiles/index.js.map +1 -0
- package/dist/profiles/ops.d.ts +3 -0
- package/dist/profiles/ops.d.ts.map +1 -0
- package/dist/profiles/ops.js +33 -0
- package/dist/profiles/ops.js.map +1 -0
- package/dist/profiles/sales.d.ts +3 -0
- package/dist/profiles/sales.d.ts.map +1 -0
- package/dist/profiles/sales.js +30 -0
- package/dist/profiles/sales.js.map +1 -0
- package/dist/profiles/support.d.ts +3 -0
- package/dist/profiles/support.d.ts.map +1 -0
- package/dist/profiles/support.js +28 -0
- package/dist/profiles/support.js.map +1 -0
- package/dist/rag/ObsidianRAGProvider.js +4 -4
- package/dist/rag/ObsidianRAGProvider.js.map +1 -1
- package/dist/rag/VaultIndexer.d.ts.map +1 -1
- package/dist/rag/VaultIndexer.js +4 -1
- package/dist/rag/VaultIndexer.js.map +1 -1
- package/dist/rag/VaultWriter.d.ts +1 -0
- package/dist/rag/VaultWriter.d.ts.map +1 -1
- package/dist/rag/VaultWriter.js +8 -3
- package/dist/rag/VaultWriter.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,187 +1,522 @@
|
|
|
1
1
|
# @backendkit-labs/agent-enterprise
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Enterprise-grade AI agent setup with RAG (Retrieval-Augmented Generation) over an Obsidian vault, six pre-configured department agent profiles, a vault writing tool, and a factory that wires everything into an `AgentEngine`-compatible setup.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@backendkit-labs/agent-enterprise)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install @backendkit-labs/agent-enterprise
|
|
9
|
-
```
|
|
7
|
+
## Table of contents
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick start](#quick-start)
|
|
11
|
+
- [createEnterpriseSetup](#createenterprisesetup)
|
|
12
|
+
- [Enterprise agent profiles](#enterprise-agent-profiles)
|
|
13
|
+
- [RAG pipeline](#rag-pipeline)
|
|
14
|
+
- [VaultIndexer](#vaultindexer)
|
|
15
|
+
- [VaultWriter](#vaultwriter)
|
|
16
|
+
- [Embedders](#embedders)
|
|
17
|
+
- [ObsidianRAGProvider](#obsidianragprovider)
|
|
18
|
+
- [VectorStore](#vectorstore)
|
|
19
|
+
- [Full production example with AgentServer](#full-production-example-with-agentserver)
|
|
12
20
|
|
|
13
21
|
---
|
|
14
22
|
|
|
15
|
-
##
|
|
23
|
+
## Installation
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
```bash
|
|
26
|
+
npm install @backendkit-labs/agent-enterprise @backendkit-labs/agent-core
|
|
27
|
+
```
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
29
|
+
For the full web stack:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @backendkit-labs/agent-enterprise @backendkit-labs/agent-core @backendkit-labs/agent-web
|
|
33
|
+
```
|
|
23
34
|
|
|
24
35
|
---
|
|
25
36
|
|
|
26
|
-
## Quick start
|
|
37
|
+
## Quick start
|
|
27
38
|
|
|
28
|
-
```
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
39
|
+
```typescript
|
|
40
|
+
import { createEnterpriseSetup } from '@backendkit-labs/agent-enterprise';
|
|
41
|
+
import { ProviderRegistry } from '@backendkit-labs/agent-core';
|
|
42
|
+
import { AgentServer } from '@backendkit-labs/agent-web';
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
// 1. Configure your LLM providers
|
|
45
|
+
const providers = new ProviderRegistry();
|
|
46
|
+
providers.register('openai', myOpenAIProvider);
|
|
47
|
+
|
|
48
|
+
// 2. Create the enterprise setup
|
|
49
|
+
const enterprise = createEnterpriseSetup({
|
|
50
|
+
vaultPath: '/shared/obsidian-vault',
|
|
51
|
+
providers,
|
|
52
|
+
defaultProvider: 'openai',
|
|
36
53
|
});
|
|
37
54
|
|
|
38
|
-
// Index the vault (
|
|
39
|
-
await
|
|
55
|
+
// 3. Index the vault (once at startup — subsequent runs only re-index changed files)
|
|
56
|
+
await enterprise.indexAll({ verbose: true });
|
|
40
57
|
|
|
41
|
-
//
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
// 4. Start the web server
|
|
59
|
+
const server = new AgentServer({
|
|
60
|
+
port: 3000,
|
|
61
|
+
engineFactory: enterprise.engineFactory,
|
|
62
|
+
cors: '*',
|
|
63
|
+
});
|
|
45
64
|
|
|
46
|
-
|
|
65
|
+
await server.start();
|
|
66
|
+
```
|
|
47
67
|
|
|
48
68
|
---
|
|
49
69
|
|
|
50
|
-
##
|
|
70
|
+
## createEnterpriseSetup
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
import { ObsidianRAGProvider, VaultWriter } from '@backendkit-labs/agent-enterprise';
|
|
72
|
+
The main factory. Returns `{ indexAll, engineFactory }`.
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
const writer = new VaultWriter({ vaultPath: '/vault' });
|
|
74
|
+
### Options
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
```typescript
|
|
77
|
+
interface EnterpriseSetupOptions {
|
|
78
|
+
// Required
|
|
79
|
+
vaultPath: string; // absolute path to the Obsidian vault
|
|
80
|
+
providers: ProviderRegistry;
|
|
81
|
+
defaultProvider: string; // provider ID used when no per-agent override is set
|
|
61
82
|
|
|
62
|
-
//
|
|
63
|
-
|
|
83
|
+
// Optional
|
|
84
|
+
indexDir?: string; // where to store index files
|
|
85
|
+
// default: ~/.bk-agent/rag/enterprise/
|
|
86
|
+
embedder?: Embedder; // custom embedder, default: SimpleEmbedder
|
|
87
|
+
sessionsDir?: string; // per-session memory dir
|
|
88
|
+
// default: ~/.bk-agent/sessions/
|
|
89
|
+
extraProfiles?: AgentProfile[]; // add custom agent profiles alongside the 6 defaults
|
|
90
|
+
maxIterations?: number; // per-engine run limit, default: 20
|
|
91
|
+
}
|
|
64
92
|
```
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
### Return value
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
interface EnterpriseSetup {
|
|
98
|
+
// Call once at startup (or periodically to pick up new vault notes)
|
|
99
|
+
indexAll(opts?: { verbose?: boolean }): Promise<void>;
|
|
100
|
+
|
|
101
|
+
// Compatible with AgentServer's engineFactory option
|
|
102
|
+
engineFactory: (sessionId: string, transport: Transport) => AgentEngine;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### What gets created per session
|
|
107
|
+
|
|
108
|
+
Each call to `engineFactory` assembles a fresh, isolated `AgentEngine` with:
|
|
109
|
+
|
|
110
|
+
- One `ObsidianRAGProvider` per department scoped to that department's vault folders
|
|
111
|
+
- One global `ObsidianRAGProvider` for the General agent (all vault folders)
|
|
112
|
+
- A shared `VaultWriter` for persisting knowledge back to the vault
|
|
113
|
+
- All six enterprise `AgentProfile`s plus any `extraProfiles`
|
|
114
|
+
- Per-session episodic, semantic, and procedural `MemorySystem` stored in `sessionsDir/<sessionId>/`
|
|
67
115
|
|
|
68
|
-
```markdown
|
|
69
|
-
---
|
|
70
|
-
title: "Cache Decision for RAG Embeddings"
|
|
71
|
-
author: "agent/analyst"
|
|
72
|
-
date: 2026-06-10
|
|
73
|
-
tags: ["área/rag", "tipo/decisión"]
|
|
74
|
-
description: "LRU in-memory cache chosen over persistent or semantic cache"
|
|
75
116
|
---
|
|
76
117
|
|
|
77
|
-
##
|
|
78
|
-
|
|
118
|
+
## Enterprise agent profiles
|
|
119
|
+
|
|
120
|
+
Six department profiles are built in. Each has a system prompt, a scoped RAG tool, and an optional provider override for on-prem data isolation.
|
|
121
|
+
|
|
122
|
+
| Profile ID | Agent Name | RAG tool | Default provider |
|
|
123
|
+
|-----------|-----------|----------|-----------------|
|
|
124
|
+
| `general` | General Assistant | `search_kb` (global vault) | `defaultProvider` |
|
|
125
|
+
| `support` | Support Agent | `search_support_kb` | `defaultProvider` |
|
|
126
|
+
| `hr` | HR Agent | `search_hr_kb` | `local` (sensitive) |
|
|
127
|
+
| `sales` | Sales Agent | `search_sales_kb` | `defaultProvider` |
|
|
128
|
+
| `finance` | Finance Agent | `search_finance_kb` | `local` (sensitive) |
|
|
129
|
+
| `ops` | Operations Agent | `search_ops_kb` | `defaultProvider` |
|
|
130
|
+
|
|
131
|
+
HR and Finance default to the `local` provider so sensitive payroll and financial data never leaves your network.
|
|
132
|
+
|
|
133
|
+
### Using profiles individually
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import {
|
|
137
|
+
GENERAL_PROFILE,
|
|
138
|
+
SUPPORT_PROFILE,
|
|
139
|
+
HR_PROFILE,
|
|
140
|
+
SALES_PROFILE,
|
|
141
|
+
FINANCE_PROFILE,
|
|
142
|
+
OPS_PROFILE,
|
|
143
|
+
ALL_ENTERPRISE_PROFILES,
|
|
144
|
+
ENTERPRISE_TOOLS,
|
|
145
|
+
VAULT_FOLDERS,
|
|
146
|
+
} from '@backendkit-labs/agent-enterprise';
|
|
147
|
+
|
|
148
|
+
// Register only the profiles you need
|
|
149
|
+
const agents = new AgentRegistry();
|
|
150
|
+
agents.register(GENERAL_PROFILE);
|
|
151
|
+
agents.register(SUPPORT_PROFILE);
|
|
152
|
+
agents.register({ ...HR_PROFILE, provider: 'ollama' }); // force on-prem
|
|
153
|
+
agents.register({ ...FINANCE_PROFILE, provider: 'ollama' }); // force on-prem
|
|
154
|
+
|
|
155
|
+
// Tool name constants
|
|
156
|
+
ENTERPRISE_TOOLS.SEARCH_KB; // 'search_kb'
|
|
157
|
+
ENTERPRISE_TOOLS.SEARCH_SUPPORT; // 'search_support_kb'
|
|
158
|
+
ENTERPRISE_TOOLS.SEARCH_HR; // 'search_hr_kb'
|
|
159
|
+
ENTERPRISE_TOOLS.SEARCH_SALES; // 'search_sales_kb'
|
|
160
|
+
ENTERPRISE_TOOLS.SEARCH_FINANCE; // 'search_finance_kb'
|
|
161
|
+
ENTERPRISE_TOOLS.SEARCH_OPS; // 'search_ops_kb'
|
|
162
|
+
|
|
163
|
+
// Vault folder name constants
|
|
164
|
+
VAULT_FOLDERS.GENERAL; // 'General'
|
|
165
|
+
VAULT_FOLDERS.SUPPORT; // 'Support'
|
|
166
|
+
VAULT_FOLDERS.HR; // 'HR'
|
|
167
|
+
VAULT_FOLDERS.SALES; // 'Sales'
|
|
168
|
+
VAULT_FOLDERS.FINANCE; // 'Finance'
|
|
169
|
+
VAULT_FOLDERS.OPS; // 'Operations'
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Adding custom profiles
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const enterprise = createEnterpriseSetup({
|
|
176
|
+
...opts,
|
|
177
|
+
extraProfiles: [
|
|
178
|
+
{
|
|
179
|
+
id: 'legal',
|
|
180
|
+
name: 'Legal Advisor',
|
|
181
|
+
systemPrompt: `You are a legal knowledge assistant.
|
|
182
|
+
Search the knowledge base for relevant precedents and policies.
|
|
183
|
+
Always recommend consulting a licensed attorney for case-specific advice.`,
|
|
184
|
+
tools: ['search_kb'],
|
|
185
|
+
provider: 'local', // sensitive — stays on-prem
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: 'engineering',
|
|
189
|
+
name: 'Engineering Assistant',
|
|
190
|
+
systemPrompt: 'You are a software engineering assistant with access to our internal technical documentation.',
|
|
191
|
+
tools: ['search_kb', 'write_vault'],
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
});
|
|
79
195
|
```
|
|
80
196
|
|
|
81
197
|
---
|
|
82
198
|
|
|
83
|
-
##
|
|
199
|
+
## RAG pipeline
|
|
84
200
|
|
|
85
|
-
|
|
201
|
+
The RAG pipeline works in two phases: **indexing** and **search**.
|
|
86
202
|
|
|
87
|
-
|
|
88
|
-
import { ObsidianRAGProvider, type Embedder } from '@backendkit-labs/agent-enterprise';
|
|
203
|
+
### Indexing phase
|
|
89
204
|
|
|
90
|
-
|
|
91
|
-
readonly model = 'my-model-v1';
|
|
92
|
-
async embed(texts: string[]): Promise<number[][]> { /* ... */ }
|
|
93
|
-
async embedOne(text: string): Promise<number[]> { /* ... */ }
|
|
94
|
-
}
|
|
205
|
+
At startup, `indexAll()` walks each vault folder, chunks the markdown files, embeds each chunk with the configured embedder, and saves the index to disk as JSON.
|
|
95
206
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
207
|
+
```typescript
|
|
208
|
+
// Full or incremental re-index (skips unchanged files)
|
|
209
|
+
await enterprise.indexAll({ verbose: true });
|
|
210
|
+
// [VaultIndexer] Indexed 142 files, 1,847 chunks in 4.2s (38 skipped, unchanged)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Search phase
|
|
214
|
+
|
|
215
|
+
When an agent's RAG tool is called, it performs cosine-similarity search over the pre-built index and injects the top-K chunks as context into the LLM prompt:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
User: "What is our parental leave policy?"
|
|
219
|
+
→ HR agent selected
|
|
220
|
+
→ search_hr_kb("parental leave policy")
|
|
221
|
+
→ Top 5 chunks from HR/ and General/ folders returned
|
|
222
|
+
→ LLM answers using the retrieved excerpts as grounding context
|
|
100
223
|
```
|
|
101
224
|
|
|
102
225
|
---
|
|
103
226
|
|
|
104
|
-
##
|
|
227
|
+
## VaultIndexer
|
|
105
228
|
|
|
106
|
-
|
|
229
|
+
Use `VaultIndexer` directly for fine-grained control over indexing.
|
|
107
230
|
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
vaultPath:
|
|
113
|
-
|
|
114
|
-
|
|
231
|
+
```typescript
|
|
232
|
+
import { VaultIndexer } from '@backendkit-labs/agent-enterprise';
|
|
233
|
+
|
|
234
|
+
const indexer = new VaultIndexer({
|
|
235
|
+
vaultPath: '/shared/obsidian-vault',
|
|
236
|
+
indexPath: '/cache/support-index.json',
|
|
237
|
+
embedder: myEmbedder,
|
|
238
|
+
folders: ['Support', 'General'], // only index these folders (omit for all)
|
|
239
|
+
chunkSize: 500, // tokens per chunk
|
|
240
|
+
chunkOverlap: 50, // overlap between adjacent chunks
|
|
115
241
|
});
|
|
242
|
+
|
|
243
|
+
await indexer.index({ verbose: true });
|
|
244
|
+
|
|
245
|
+
const stats = indexer.getStats();
|
|
246
|
+
// { files: 42, chunks: 587, lastIndexedAt: '2026-06-11T09:00:00.000Z' }
|
|
116
247
|
```
|
|
117
248
|
|
|
118
|
-
|
|
249
|
+
### Incremental re-indexing
|
|
250
|
+
|
|
251
|
+
The indexer tracks file modification times. Re-running `index()` only processes changed or new files:
|
|
119
252
|
|
|
120
|
-
|
|
253
|
+
```typescript
|
|
254
|
+
// First run — full index (may take seconds to minutes depending on vault size)
|
|
255
|
+
await indexer.index({ verbose: true });
|
|
121
256
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
folders?: string[]; // sub-folders to index (default: all)
|
|
126
|
-
indexPath?: string; // where to save the vector index JSON
|
|
127
|
-
embedder?: Embedder; // custom embedder (overrides ollamaHost/embeddingModel)
|
|
128
|
-
ollamaHost?: string; // default: http://localhost:11434
|
|
129
|
-
embeddingModel?: string; // default: nomic-embed-text
|
|
130
|
-
topK?: number; // max results per search (default: 5)
|
|
131
|
-
minScore?: number; // min cosine similarity 0–1 (default: 0.3)
|
|
132
|
-
excludeTags?: string[]; // frontmatter tags to skip (default: ['skill'])
|
|
133
|
-
})
|
|
257
|
+
// Subsequent runs — only re-indexes changed files (very fast)
|
|
258
|
+
await indexer.index({ verbose: true });
|
|
259
|
+
// [VaultIndexer] 3 files changed, re-indexed 28 chunks
|
|
134
260
|
```
|
|
135
261
|
|
|
136
262
|
---
|
|
137
263
|
|
|
138
|
-
## VaultWriter
|
|
264
|
+
## VaultWriter
|
|
265
|
+
|
|
266
|
+
`VaultWriter` lets agents persist knowledge back to the Obsidian vault — closing the knowledge loop.
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { VaultWriter } from '@backendkit-labs/agent-enterprise';
|
|
270
|
+
|
|
271
|
+
const writer = new VaultWriter({
|
|
272
|
+
vaultPath: '/shared/obsidian-vault',
|
|
273
|
+
allowedFolders: ['General', 'Support'], // restrict where agents can write
|
|
274
|
+
});
|
|
139
275
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
vaultPath: string; // must match the ObsidianRAGProvider vaultPath
|
|
143
|
-
agentFolder?: string; // sub-folder for agent notes (default: 'agentes')
|
|
144
|
-
})
|
|
276
|
+
// Create a ToolDefinition the engine can call
|
|
277
|
+
const writeTool = writer.createTool('general'); // 'write_vault' tool
|
|
145
278
|
|
|
146
|
-
|
|
147
|
-
|
|
279
|
+
// Write directly (from non-agent code)
|
|
280
|
+
await writer.writeNote({
|
|
281
|
+
folder: 'General',
|
|
282
|
+
filename: 'api-auth-pattern.md',
|
|
283
|
+
content: '# API Auth Pattern\n\nAll endpoints require a Bearer token...',
|
|
284
|
+
tags: ['api', 'patterns', 'security'],
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### How agents use VaultWriter
|
|
289
|
+
|
|
290
|
+
Agents with `write_vault` in their tool list can invoke it directly in conversation:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
User: "Document the new API authentication pattern we agreed on"
|
|
294
|
+
→ General agent
|
|
295
|
+
→ LLM calls write_vault({
|
|
296
|
+
folder: "General",
|
|
297
|
+
filename: "api-auth-2026.md",
|
|
298
|
+
content: "# API Auth Pattern\n\n..."
|
|
299
|
+
})
|
|
300
|
+
→ File created/updated in the vault
|
|
301
|
+
→ LLM: "I've documented the auth pattern in General/api-auth-2026.md"
|
|
148
302
|
```
|
|
149
303
|
|
|
150
304
|
---
|
|
151
305
|
|
|
152
|
-
##
|
|
306
|
+
## Embedders
|
|
307
|
+
|
|
308
|
+
Embedders convert text strings into float vectors for similarity search.
|
|
309
|
+
|
|
310
|
+
### SimpleEmbedder (default — no external dependencies)
|
|
311
|
+
|
|
312
|
+
A deterministic, hash-based embedder. Requires no API key or running service. Lower accuracy than neural models but always available and zero-latency:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import { SimpleEmbedder } from '@backendkit-labs/agent-enterprise';
|
|
316
|
+
|
|
317
|
+
const embedder = new SimpleEmbedder();
|
|
318
|
+
// Good for: prototyping, CI/CD, air-gapped systems, and fallback
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### OllamaEmbedder (recommended for production)
|
|
322
|
+
|
|
323
|
+
Uses a local Ollama embedding model for high-quality semantic embeddings. Requires a running Ollama instance with an embedding model installed:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
ollama pull nomic-embed-text # 274 MB — general purpose, fast
|
|
327
|
+
ollama pull mxbai-embed-large # 669 MB — higher accuracy
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { OllamaEmbedder, OLLAMA_EMBED_DEFAULT_HOST, OLLAMA_EMBED_DEFAULT_MODEL } from '@backendkit-labs/agent-enterprise';
|
|
153
332
|
|
|
154
|
-
|
|
333
|
+
const embedder = new OllamaEmbedder({
|
|
334
|
+
host: 'http://localhost:11434', // default: OLLAMA_EMBED_DEFAULT_HOST
|
|
335
|
+
model: 'nomic-embed-text', // default: OLLAMA_EMBED_DEFAULT_MODEL
|
|
336
|
+
});
|
|
155
337
|
|
|
338
|
+
const enterprise = createEnterpriseSetup({
|
|
339
|
+
vaultPath: '/vault',
|
|
340
|
+
providers,
|
|
341
|
+
defaultProvider: 'local',
|
|
342
|
+
embedder,
|
|
343
|
+
});
|
|
156
344
|
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
345
|
+
|
|
346
|
+
### Custom embedder (OpenAI, Cohere, Hugging Face, etc.)
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import type { Embedder } from '@backendkit-labs/agent-enterprise';
|
|
350
|
+
|
|
351
|
+
class OpenAIEmbedder implements Embedder {
|
|
352
|
+
async embed(texts: string[]): Promise<number[][]> {
|
|
353
|
+
const res = await openai.embeddings.create({
|
|
354
|
+
model: 'text-embedding-3-small',
|
|
355
|
+
input: texts,
|
|
356
|
+
});
|
|
357
|
+
return res.data.map(d => d.embedding);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const enterprise = createEnterpriseSetup({
|
|
362
|
+
...opts,
|
|
363
|
+
embedder: new OpenAIEmbedder(),
|
|
364
|
+
});
|
|
163
365
|
```
|
|
164
366
|
|
|
165
|
-
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## ObsidianRAGProvider
|
|
370
|
+
|
|
371
|
+
Combines `VaultIndexer` + `VectorStore` in one class with a search API and a tool factory. Use it directly for custom RAG configurations.
|
|
166
372
|
|
|
167
|
-
```
|
|
168
|
-
|
|
373
|
+
```typescript
|
|
374
|
+
import { ObsidianRAGProvider } from '@backendkit-labs/agent-enterprise';
|
|
375
|
+
|
|
376
|
+
const rag = new ObsidianRAGProvider({
|
|
377
|
+
vaultPath: '/shared/obsidian-vault',
|
|
378
|
+
indexPath: '/cache/support-index.json',
|
|
379
|
+
embedder: new OllamaEmbedder({ model: 'nomic-embed-text' }),
|
|
380
|
+
folders: ['Support', 'General'],
|
|
381
|
+
topK: 5, // return top 5 results
|
|
382
|
+
minScore: 0.15, // discard results below this similarity threshold
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Index the vault
|
|
386
|
+
await rag.index({ verbose: true });
|
|
387
|
+
|
|
388
|
+
// Search
|
|
389
|
+
const results = await rag.search('How do I reset my password?');
|
|
390
|
+
// [
|
|
391
|
+
// { content: "To reset your password...", score: 0.82, source: "Support/password-reset.md" },
|
|
392
|
+
// { content: "Users can request a reset...", score: 0.71, source: "General/user-guide.md" },
|
|
393
|
+
// ]
|
|
394
|
+
|
|
395
|
+
// Create a typed ToolDefinition for the engine
|
|
396
|
+
const searchTool = rag.createTool('search_support_kb');
|
|
397
|
+
// → ToolDefinition with name 'search_support_kb' that calls rag.search()
|
|
169
398
|
```
|
|
170
399
|
|
|
171
400
|
---
|
|
172
401
|
|
|
173
|
-
##
|
|
402
|
+
## VectorStore
|
|
403
|
+
|
|
404
|
+
Low-level cosine-similarity search engine. Use it when you have your own embedding pipeline.
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
import { VectorStore } from '@backendkit-labs/agent-enterprise';
|
|
408
|
+
import type { VectorChunk, SearchResult } from '@backendkit-labs/agent-enterprise';
|
|
409
|
+
|
|
410
|
+
const store = new VectorStore();
|
|
411
|
+
|
|
412
|
+
// Add pre-embedded chunks
|
|
413
|
+
store.add([
|
|
414
|
+
{ id: 'c1', content: 'Password reset procedure...', embedding: [...512 floats...], source: 'support.md' },
|
|
415
|
+
{ id: 'c2', content: 'Password policy requires...', embedding: [...512 floats...], source: 'policy.md' },
|
|
416
|
+
]);
|
|
174
417
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
4. Chunks each file by `##` headings (max 500 words per chunk)
|
|
179
|
-
5. Stores vectors + metadata in a single JSON file on disk
|
|
418
|
+
// Search by query embedding
|
|
419
|
+
const queryEmbeddings = await embedder.embed(['reset password steps']);
|
|
420
|
+
const results: SearchResult[] = store.search(queryEmbeddings[0], { topK: 3, minScore: 0.1 });
|
|
180
421
|
|
|
181
|
-
|
|
422
|
+
// Persist index to disk
|
|
423
|
+
store.saveToFile('/cache/my-index.json');
|
|
424
|
+
|
|
425
|
+
// Load from disk (on restart)
|
|
426
|
+
const loaded = VectorStore.loadFromFile('/cache/my-index.json');
|
|
427
|
+
```
|
|
182
428
|
|
|
183
429
|
---
|
|
184
430
|
|
|
185
|
-
##
|
|
431
|
+
## Full production example with AgentServer
|
|
432
|
+
|
|
433
|
+
A complete on-prem enterprise deployment with Ollama embeddings, DeepSeek for general agents, local Ollama for HR/Finance, Redis sessions, and JWT auth:
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
import { createEnterpriseSetup, OllamaEmbedder } from '@backendkit-labs/agent-enterprise';
|
|
437
|
+
import { ProviderRegistry } from '@backendkit-labs/agent-core';
|
|
438
|
+
import { AgentServer, JwtAuth, TriggerBus, RedisSessionMetaStore } from '@backendkit-labs/agent-web';
|
|
439
|
+
import Redis from 'ioredis';
|
|
440
|
+
|
|
441
|
+
// ── LLM Providers ─────────────────────────────────────────────────────────────
|
|
442
|
+
|
|
443
|
+
const providers = new ProviderRegistry();
|
|
444
|
+
|
|
445
|
+
// Cloud: general, support, sales, ops
|
|
446
|
+
providers.register('deepseek', new DeepSeekProvider({
|
|
447
|
+
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
448
|
+
model: 'deepseek-chat',
|
|
449
|
+
}));
|
|
450
|
+
|
|
451
|
+
// On-prem: HR and Finance (sensitive data)
|
|
452
|
+
providers.register('local', new OllamaProvider({
|
|
453
|
+
host: 'http://ollama.internal:11434',
|
|
454
|
+
model: 'llama3.2',
|
|
455
|
+
}));
|
|
456
|
+
|
|
457
|
+
// ── Enterprise Setup ───────────────────────────────────────────────────────────
|
|
458
|
+
|
|
459
|
+
const enterprise = createEnterpriseSetup({
|
|
460
|
+
vaultPath: process.env.VAULT_PATH!,
|
|
461
|
+
providers,
|
|
462
|
+
defaultProvider: 'deepseek',
|
|
463
|
+
embedder: new OllamaEmbedder({
|
|
464
|
+
host: 'http://ollama.internal:11434',
|
|
465
|
+
model: 'nomic-embed-text',
|
|
466
|
+
}),
|
|
467
|
+
indexDir: '/var/bk-agent/rag-indexes',
|
|
468
|
+
sessionsDir: '/var/bk-agent/sessions',
|
|
469
|
+
maxIterations: 20,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
await enterprise.indexAll({ verbose: true });
|
|
473
|
+
|
|
474
|
+
// Re-index every night at 2 AM to pick up new vault notes
|
|
475
|
+
import { CronJob } from 'node-cron';
|
|
476
|
+
CronJob.schedule('0 2 * * *', () => enterprise.indexAll());
|
|
477
|
+
|
|
478
|
+
// ── Infrastructure ─────────────────────────────────────────────────────────────
|
|
479
|
+
|
|
480
|
+
const redis = new Redis(process.env.REDIS_URL!);
|
|
481
|
+
const jwt = new JwtAuth({ secret: process.env.JWT_SECRET!, sessionIdClaim: 'sub' });
|
|
482
|
+
const triggers = new TriggerBus(enterprise.engineFactory)
|
|
483
|
+
.addCron({
|
|
484
|
+
name: 'weekly-digest',
|
|
485
|
+
schedule: '0 9 * * 1',
|
|
486
|
+
buildPrompt: () => 'Summarize all knowledge base updates from the past week.',
|
|
487
|
+
onResult: (out) => intranet.post('/announcements', out),
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// ── Server ─────────────────────────────────────────────────────────────────────
|
|
491
|
+
|
|
492
|
+
const server = new AgentServer({
|
|
493
|
+
port: 3000,
|
|
494
|
+
engineFactory: enterprise.engineFactory,
|
|
495
|
+
auth: jwt.hook(),
|
|
496
|
+
store: new RedisSessionMetaStore(redis),
|
|
497
|
+
cors: ['https://intranet.company.com'],
|
|
498
|
+
rateLimiting: { max: 30, timeWindow: '1 minute' },
|
|
499
|
+
metrics: { enabled: true, prefix: 'enterprise_' },
|
|
500
|
+
maxIdleMs: 30 * 60 * 1000,
|
|
501
|
+
triggers,
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
await server.start();
|
|
505
|
+
console.log('Enterprise agent server running on :3000');
|
|
506
|
+
|
|
507
|
+
process.on('SIGTERM', () => server.stop());
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Required vault folder structure
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
/obsidian-vault
|
|
514
|
+
├── General/ ← all agents can search here
|
|
515
|
+
├── Support/ ← Support agent
|
|
516
|
+
├── HR/ ← HR agent (on-prem LLM)
|
|
517
|
+
├── Sales/ ← Sales agent
|
|
518
|
+
├── Finance/ ← Finance agent (on-prem LLM)
|
|
519
|
+
└── Operations/ ← Ops agent
|
|
520
|
+
```
|
|
186
521
|
|
|
187
|
-
|
|
522
|
+
Create these folders in Obsidian and add `.md` files. The indexer discovers all markdown files recursively.
|