@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.
Files changed (53) hide show
  1. package/README.md +447 -110
  2. package/dist/factory.d.ts +47 -0
  3. package/dist/factory.d.ts.map +1 -0
  4. package/dist/factory.js +146 -0
  5. package/dist/factory.js.map +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +17 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/profiles/constants.d.ts +22 -0
  11. package/dist/profiles/constants.d.ts.map +1 -0
  12. package/dist/profiles/constants.js +25 -0
  13. package/dist/profiles/constants.js.map +1 -0
  14. package/dist/profiles/finance.d.ts +3 -0
  15. package/dist/profiles/finance.d.ts.map +1 -0
  16. package/dist/profiles/finance.js +34 -0
  17. package/dist/profiles/finance.js.map +1 -0
  18. package/dist/profiles/general.d.ts +3 -0
  19. package/dist/profiles/general.d.ts.map +1 -0
  20. package/dist/profiles/general.js +32 -0
  21. package/dist/profiles/general.js.map +1 -0
  22. package/dist/profiles/hr.d.ts +3 -0
  23. package/dist/profiles/hr.d.ts.map +1 -0
  24. package/dist/profiles/hr.js +34 -0
  25. package/dist/profiles/hr.js.map +1 -0
  26. package/dist/profiles/index.d.ts +10 -0
  27. package/dist/profiles/index.d.ts.map +1 -0
  28. package/dist/profiles/index.js +33 -0
  29. package/dist/profiles/index.js.map +1 -0
  30. package/dist/profiles/ops.d.ts +3 -0
  31. package/dist/profiles/ops.d.ts.map +1 -0
  32. package/dist/profiles/ops.js +33 -0
  33. package/dist/profiles/ops.js.map +1 -0
  34. package/dist/profiles/sales.d.ts +3 -0
  35. package/dist/profiles/sales.d.ts.map +1 -0
  36. package/dist/profiles/sales.js +30 -0
  37. package/dist/profiles/sales.js.map +1 -0
  38. package/dist/profiles/support.d.ts +3 -0
  39. package/dist/profiles/support.d.ts.map +1 -0
  40. package/dist/profiles/support.js +28 -0
  41. package/dist/profiles/support.js.map +1 -0
  42. package/dist/rag/SimpleEmbedder.d.ts +23 -0
  43. package/dist/rag/SimpleEmbedder.d.ts.map +1 -0
  44. package/dist/rag/SimpleEmbedder.js +65 -0
  45. package/dist/rag/SimpleEmbedder.js.map +1 -0
  46. package/dist/rag/VaultIndexer.d.ts.map +1 -1
  47. package/dist/rag/VaultIndexer.js +4 -1
  48. package/dist/rag/VaultIndexer.js.map +1 -1
  49. package/dist/rag/VaultWriter.d.ts +1 -0
  50. package/dist/rag/VaultWriter.d.ts.map +1 -1
  51. package/dist/rag/VaultWriter.js +8 -3
  52. package/dist/rag/VaultWriter.js.map +1 -1
  53. package/package.json +35 -35
package/README.md CHANGED
@@ -1,185 +1,522 @@
1
1
  # @backendkit-labs/agent-enterprise
2
2
 
3
- Enterprise knowledge layer for the BackendKit Agent Framework — local RAG over Obsidian vaults, shared knowledge vault with agent write-back, and pluggable embedders.
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
- ```bash
6
- npm install @backendkit-labs/agent-enterprise
7
- ```
5
+ [![npm](https://img.shields.io/npm/v/@backendkit-labs/agent-enterprise)](https://www.npmjs.com/package/@backendkit-labs/agent-enterprise)
8
6
 
9
- > Requires `@backendkit-labs/agent-core`. Works with any LLM provider — no cloud dependency required.
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
- ## What it does
23
+ ## Installation
14
24
 
15
- Gives your agents a **shared, persistent knowledge base** backed by Markdown files:
25
+ ```bash
26
+ npm install @backendkit-labs/agent-enterprise @backendkit-labs/agent-core
27
+ ```
16
28
 
17
- - **Read** — agents search the vault semantically (`search_knowledge` tool)
18
- - **Write** — agents contribute new knowledge back to the vault (`write_knowledge` tool)
19
- - **Index** — incremental indexing by file mtime; only re-embeds new or modified files
20
- - **Human-readable** — the vault is plain Markdown, openable in Obsidian or any editor
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 — RAG over an Obsidian vault
37
+ ## Quick start
25
38
 
26
- ```ts
27
- import { AgentEngine, ToolRegistry } from '@backendkit-labs/agent-core';
28
- import { ObsidianRAGProvider } from '@backendkit-labs/agent-enterprise';
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
- const rag = new ObsidianRAGProvider({
31
- vaultPath: '/path/to/your/vault',
32
- ollamaHost: 'http://localhost:11434', // default
33
- embeddingModel: 'nomic-embed-text', // default
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 (incremental — only changed files on subsequent runs)
37
- await rag.index({ verbose: true });
55
+ // 3. Index the vault (once at startup — subsequent runs only re-index changed files)
56
+ await enterprise.indexAll({ verbose: true });
38
57
 
39
- // Register the search_knowledge tool with your engine
40
- const tools = new ToolRegistry();
41
- tools.register(rag.createTool());
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
- The agent calls `search_knowledge` automatically when it needs information from the vault.
65
+ await server.start();
66
+ ```
45
67
 
46
68
  ---
47
69
 
48
- ## Shared vault with agent write-back
70
+ ## createEnterpriseSetup
49
71
 
50
- ```ts
51
- import { ObsidianRAGProvider, VaultWriter } from '@backendkit-labs/agent-enterprise';
72
+ The main factory. Returns `{ indexAll, engineFactory }`.
52
73
 
53
- const rag = new ObsidianRAGProvider({ vaultPath: '/vault', ...opts });
54
- const writer = new VaultWriter({ vaultPath: '/vault' });
74
+ ### Options
55
75
 
56
- const tools = new ToolRegistry();
57
- tools.register(rag.createTool()); // search_knowledge
58
- tools.register(writer.createTool('analyst')); // write_knowledge — baked in with agent id
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
- // After the agent writes a note, re-index to make it searchable:
61
- await rag.index();
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
- Agent-written notes land in `<vaultPath>/agentes/` with standard frontmatter:
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
- ## Context
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
- ## Custom embedder — no Ollama required
199
+ ## RAG pipeline
82
200
 
83
- Pass any object that implements `Embedder` to skip Ollama:
201
+ The RAG pipeline works in two phases: **indexing** and **search**.
84
202
 
85
- ```ts
86
- import { ObsidianRAGProvider, type Embedder } from '@backendkit-labs/agent-enterprise';
203
+ ### Indexing phase
87
204
 
88
- class MyEmbedder implements Embedder {
89
- readonly model = 'my-model-v1';
90
- async embed(texts: string[]): Promise<number[][]> { /* ... */ }
91
- async embedOne(text: string): Promise<number[]> { /* ... */ }
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
- const rag = new ObsidianRAGProvider({
95
- vaultPath: '/vault',
96
- embedder: new MyEmbedder(), // ollamaHost and embeddingModel are ignored
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
- ## SimpleEmbedder — local testing without Ollama
227
+ ## VaultIndexer
103
228
 
104
- For tests and CI where Ollama is not available:
229
+ Use `VaultIndexer` directly for fine-grained control over indexing.
105
230
 
106
- ```ts
107
- // Not exported from the package — copy from pilot/src/embedders/SimpleEmbedder.ts
108
- // TF-IDF feature hashing, 256 dims, pure Node.js, zero dependencies
109
- const rag = new ObsidianRAGProvider({
110
- vaultPath: '/vault',
111
- embedder: new SimpleEmbedder(),
112
- minScore: 0.1, // lower threshold for keyword-based vectors
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
- ## ObsidianRAGProvider options
251
+ The indexer tracks file modification times. Re-running `index()` only processes changed or new files:
119
252
 
120
- ```ts
121
- new ObsidianRAGProvider({
122
- vaultPath: string; // absolute path to vault directory
123
- folders?: string[]; // sub-folders to index (default: all)
124
- indexPath?: string; // where to save the vector index JSON
125
- embedder?: Embedder; // custom embedder (overrides ollamaHost/embeddingModel)
126
- ollamaHost?: string; // default: http://localhost:11434
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 options
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
- ```ts
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
- writer.createTool(agentId: string): ToolDefinition
145
- // Returns write_knowledge tool with agentId baked into each note's author field
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
- ## Vault structure
306
+ ## Embedders
307
+
308
+ Embedders convert text strings into float vectors for similarity search.
309
+
310
+ ### SimpleEmbedder (default — no external dependencies)
151
311
 
152
- Recommended layout for enterprise deployments:
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
- vault/
156
- rrhh/ ← HR domain — only HR Agent indexed here
157
- ventas/ ← Sales domain
158
- ops/ ← Operations
159
- compartido/ ← Cross-domain, all agents read
160
- agentes/ ← Auto-created — agent-written notes land here
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
- Mount only the relevant folders per agent:
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
- ```ts
166
- new ObsidianRAGProvider({ vaultPath, folders: ['ventas', 'compartido', 'agentes'] })
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
- ## How indexing works
369
+ ## ObsidianRAGProvider
172
370
 
173
- 1. `VaultIndexer` scans `.md` files and reads their `mtime`
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
- The JSON store scales to ~5–10k chunks. For larger vaults, use a proper vector DB (pgvector, Qdrant) with a custom `Embedder` adapter.
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
- ## License
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
- MIT © [BackendKit Labs](https://github.com/BackendKit-labs)
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