@backendkit-labs/agent-enterprise 0.2.0 → 0.3.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 +447 -110
- 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 +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -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/SimpleEmbedder.d.ts +23 -0
- package/dist/rag/SimpleEmbedder.d.ts.map +1 -0
- package/dist/rag/SimpleEmbedder.js +65 -0
- package/dist/rag/SimpleEmbedder.js.map +1 -0
- 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 +35 -35
package/README.md
CHANGED
|
@@ -1,185 +1,522 @@
|
|
|
1
1
|
# @backendkit-labs/agent-enterprise
|
|
2
2
|
|
|
3
|
-
Enterprise
|
|
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
|
-
|
|
6
|
-
npm install @backendkit-labs/agent-enterprise
|
|
7
|
-
```
|
|
5
|
+
[](https://www.npmjs.com/package/@backendkit-labs/agent-enterprise)
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
## Table of contents
|
|
8
|
+
|
|
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)
|
|
10
20
|
|
|
11
21
|
---
|
|
12
22
|
|
|
13
|
-
##
|
|
23
|
+
## Installation
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
```bash
|
|
26
|
+
npm install @backendkit-labs/agent-enterprise @backendkit-labs/agent-core
|
|
27
|
+
```
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
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
|
+
```
|
|
21
34
|
|
|
22
35
|
---
|
|
23
36
|
|
|
24
|
-
## Quick start
|
|
37
|
+
## Quick start
|
|
25
38
|
|
|
26
|
-
```
|
|
27
|
-
import {
|
|
28
|
-
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';
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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',
|
|
34
53
|
});
|
|
35
54
|
|
|
36
|
-
// Index the vault (
|
|
37
|
-
await
|
|
55
|
+
// 3. Index the vault (once at startup — subsequent runs only re-index changed files)
|
|
56
|
+
await enterprise.indexAll({ verbose: true });
|
|
38
57
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
// 4. Start the web server
|
|
59
|
+
const server = new AgentServer({
|
|
60
|
+
port: 3000,
|
|
61
|
+
engineFactory: enterprise.engineFactory,
|
|
62
|
+
cors: '*',
|
|
63
|
+
});
|
|
43
64
|
|
|
44
|
-
|
|
65
|
+
await server.start();
|
|
66
|
+
```
|
|
45
67
|
|
|
46
68
|
---
|
|
47
69
|
|
|
48
|
-
##
|
|
70
|
+
## createEnterpriseSetup
|
|
49
71
|
|
|
50
|
-
|
|
51
|
-
import { ObsidianRAGProvider, VaultWriter } from '@backendkit-labs/agent-enterprise';
|
|
72
|
+
The main factory. Returns `{ indexAll, engineFactory }`.
|
|
52
73
|
|
|
53
|
-
|
|
54
|
-
const writer = new VaultWriter({ vaultPath: '/vault' });
|
|
74
|
+
### Options
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
59
82
|
|
|
60
|
-
//
|
|
61
|
-
|
|
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
|
+
}
|
|
62
92
|
```
|
|
63
93
|
|
|
64
|
-
|
|
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>/`
|
|
65
115
|
|
|
66
|
-
```markdown
|
|
67
|
-
---
|
|
68
|
-
title: "Cache Decision for RAG Embeddings"
|
|
69
|
-
author: "agent/analyst"
|
|
70
|
-
date: 2026-06-10
|
|
71
|
-
tags: ["área/rag", "tipo/decisión"]
|
|
72
|
-
description: "LRU in-memory cache chosen over persistent or semantic cache"
|
|
73
116
|
---
|
|
74
117
|
|
|
75
|
-
##
|
|
76
|
-
|
|
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
|
+
});
|
|
77
195
|
```
|
|
78
196
|
|
|
79
197
|
---
|
|
80
198
|
|
|
81
|
-
##
|
|
199
|
+
## RAG pipeline
|
|
82
200
|
|
|
83
|
-
|
|
201
|
+
The RAG pipeline works in two phases: **indexing** and **search**.
|
|
84
202
|
|
|
85
|
-
|
|
86
|
-
import { ObsidianRAGProvider, type Embedder } from '@backendkit-labs/agent-enterprise';
|
|
203
|
+
### Indexing phase
|
|
87
204
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
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.
|
|
206
|
+
|
|
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:
|
|
93
216
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
|
98
223
|
```
|
|
99
224
|
|
|
100
225
|
---
|
|
101
226
|
|
|
102
|
-
##
|
|
227
|
+
## VaultIndexer
|
|
103
228
|
|
|
104
|
-
|
|
229
|
+
Use `VaultIndexer` directly for fine-grained control over indexing.
|
|
105
230
|
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
vaultPath:
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
113
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' }
|
|
114
247
|
```
|
|
115
248
|
|
|
116
|
-
|
|
249
|
+
### Incremental re-indexing
|
|
117
250
|
|
|
118
|
-
|
|
251
|
+
The indexer tracks file modification times. Re-running `index()` only processes changed or new files:
|
|
119
252
|
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
embeddingModel?: string; // default: nomic-embed-text
|
|
128
|
-
topK?: number; // max results per search (default: 5)
|
|
129
|
-
minScore?: number; // min cosine similarity 0–1 (default: 0.3)
|
|
130
|
-
excludeTags?: string[]; // frontmatter tags to skip (default: ['skill'])
|
|
131
|
-
})
|
|
253
|
+
```typescript
|
|
254
|
+
// First run — full index (may take seconds to minutes depending on vault size)
|
|
255
|
+
await indexer.index({ verbose: true });
|
|
256
|
+
|
|
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
|
|
132
260
|
```
|
|
133
261
|
|
|
134
262
|
---
|
|
135
263
|
|
|
136
|
-
## 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
|
+
});
|
|
275
|
+
|
|
276
|
+
// Create a ToolDefinition the engine can call
|
|
277
|
+
const writeTool = writer.createTool('general'); // 'write_vault' tool
|
|
278
|
+
|
|
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
|
|
137
289
|
|
|
138
|
-
|
|
139
|
-
new VaultWriter({
|
|
140
|
-
vaultPath: string; // must match the ObsidianRAGProvider vaultPath
|
|
141
|
-
agentFolder?: string; // sub-folder for agent notes (default: 'agentes')
|
|
142
|
-
})
|
|
290
|
+
Agents with `write_vault` in their tool list can invoke it directly in conversation:
|
|
143
291
|
|
|
144
|
-
|
|
145
|
-
|
|
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"
|
|
146
302
|
```
|
|
147
303
|
|
|
148
304
|
---
|
|
149
305
|
|
|
150
|
-
##
|
|
306
|
+
## Embedders
|
|
307
|
+
|
|
308
|
+
Embedders convert text strings into float vectors for similarity search.
|
|
309
|
+
|
|
310
|
+
### SimpleEmbedder (default — no external dependencies)
|
|
151
311
|
|
|
152
|
-
|
|
312
|
+
A deterministic, hash-based embedder. Requires no API key or running service. Lower accuracy than neural models but always available and zero-latency:
|
|
153
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
|
|
154
319
|
```
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
161
328
|
```
|
|
162
329
|
|
|
163
|
-
|
|
330
|
+
```typescript
|
|
331
|
+
import { OllamaEmbedder, OLLAMA_EMBED_DEFAULT_HOST, OLLAMA_EMBED_DEFAULT_MODEL } from '@backendkit-labs/agent-enterprise';
|
|
332
|
+
|
|
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
|
+
});
|
|
164
337
|
|
|
165
|
-
|
|
166
|
-
|
|
338
|
+
const enterprise = createEnterpriseSetup({
|
|
339
|
+
vaultPath: '/vault',
|
|
340
|
+
providers,
|
|
341
|
+
defaultProvider: 'local',
|
|
342
|
+
embedder,
|
|
343
|
+
});
|
|
344
|
+
```
|
|
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
|
+
});
|
|
167
365
|
```
|
|
168
366
|
|
|
169
367
|
---
|
|
170
368
|
|
|
171
|
-
##
|
|
369
|
+
## ObsidianRAGProvider
|
|
172
370
|
|
|
173
|
-
|
|
174
|
-
2. Compares against stored mtimes in `VectorStore`
|
|
175
|
-
3. Only embeds files that are new or modified since last index
|
|
176
|
-
4. Chunks each file by `##` headings (max 500 words per chunk)
|
|
177
|
-
5. Stores vectors + metadata in a single JSON file on disk
|
|
371
|
+
Combines `VaultIndexer` + `VectorStore` in one class with a search API and a tool factory. Use it directly for custom RAG configurations.
|
|
178
372
|
|
|
179
|
-
|
|
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()
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
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
|
+
]);
|
|
417
|
+
|
|
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 });
|
|
421
|
+
|
|
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
|
+
```
|
|
180
428
|
|
|
181
429
|
---
|
|
182
430
|
|
|
183
|
-
##
|
|
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
|
+
```
|
|
184
521
|
|
|
185
|
-
|
|
522
|
+
Create these folders in Obsidian and add `.md` files. The indexer discovers all markdown files recursively.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AgentEngine, ProviderRegistry } from '@backendkit-labs/agent-core';
|
|
2
|
+
import type { Transport, AgentProfile } from '@backendkit-labs/agent-core';
|
|
3
|
+
import type { Embedder } from './rag/ObsidianRAGProvider';
|
|
4
|
+
export interface EnterpriseSetupOptions {
|
|
5
|
+
/** Absolute path to the shared Obsidian vault. */
|
|
6
|
+
vaultPath: string;
|
|
7
|
+
/** Directory where RAG index files are stored. Default: ~/.bk-agent/rag/enterprise/ */
|
|
8
|
+
indexDir?: string;
|
|
9
|
+
/** Embedder to use. Default: SimpleEmbedder (no Ollama required). */
|
|
10
|
+
embedder?: Embedder;
|
|
11
|
+
/** Pre-configured ProviderRegistry with at least one LLM provider. */
|
|
12
|
+
providers: ProviderRegistry;
|
|
13
|
+
/** Default provider ID to use when no per-agent override is set. */
|
|
14
|
+
defaultProvider: string;
|
|
15
|
+
/** Directory for per-session memory files. Default: ~/.bk-agent/sessions/ */
|
|
16
|
+
sessionsDir?: string;
|
|
17
|
+
/** Additional AgentProfiles to register alongside the 6 enterprise defaults. */
|
|
18
|
+
extraProfiles?: AgentProfile[];
|
|
19
|
+
/** Max iterations per engine run. Default: 20. */
|
|
20
|
+
maxIterations?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface EnterpriseSetup {
|
|
23
|
+
/** Call once at startup to index all vault folders. */
|
|
24
|
+
indexAll(opts?: {
|
|
25
|
+
verbose?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
/** EngineFactory compatible with AgentServer from @backendkit-labs/agent-web. */
|
|
28
|
+
engineFactory: (sessionId: string, transport: Transport) => AgentEngine;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a fully-wired enterprise setup with:
|
|
32
|
+
* - One RAG instance per department (scoped to its vault folders)
|
|
33
|
+
* - One global RAG for the General agent
|
|
34
|
+
* - VaultWriter shared across all agents
|
|
35
|
+
* - EngineFactory that creates a new AgentEngine per WebSocket session
|
|
36
|
+
*
|
|
37
|
+
* Usage:
|
|
38
|
+
* ```ts
|
|
39
|
+
* const enterprise = createEnterpriseSetup({ vaultPath, providers, defaultProvider });
|
|
40
|
+
* await enterprise.indexAll();
|
|
41
|
+
*
|
|
42
|
+
* const server = new AgentServer({ port: 3000, engineFactory: enterprise.engineFactory, cors: '*' });
|
|
43
|
+
* await server.start();
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function createEnterpriseSetup(opts: EnterpriseSetupOptions): EnterpriseSetup;
|
|
47
|
+
//# sourceMappingURL=factory.d.ts.map
|