@yesvara/svara 0.1.1 → 0.1.3
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/CONTRIBUTING.md +1 -1
- package/README.md +223 -15
- package/SvaraJS.png +0 -0
- package/dist/{chunk-WA3BIA3S.mjs → chunk-CCNWHBEI.mjs} +3 -251
- package/dist/chunk-GA7LHPOF.mjs +257 -0
- package/dist/cli/index.js +490 -4
- package/dist/cli/index.mjs +35 -3
- package/dist/db-PEMUBXAR.mjs +190 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -0
- package/dist/index.mjs +15 -3
- package/dist/{retriever-OTPBECGO.mjs → retriever-JYOGHA4F.mjs} +2 -1
- package/examples/03-rag-knowledge/index.ts +2 -4
- package/package.json +2 -2
- package/src/cli/commands/db.ts +267 -0
- package/src/cli/index.ts +74 -4
- package/src/core/agent.ts +12 -0
- package/svara@1.0.0 +0 -0
- package/test-rag.ts +0 -20
- package/tsx +0 -0
package/CONTRIBUTING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Contributing to SvaraJS
|
|
2
2
|
|
|
3
|
-
Thanks for your interest in contributing! We welcome all contributions
|
|
3
|
+
Thanks for your interest in contributing! We welcome all contributions such as bug reports, feature requests, documentation improvements, and pull requests.
|
|
4
4
|
|
|
5
5
|
## Code of Conduct
|
|
6
6
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
+
<img src="SvaraJS.png" alt="SvaraJS" width="400">
|
|
2
3
|
|
|
3
|
-
# @yesvara/svara
|
|
4
|
+
<!-- # @yesvara/svara -->
|
|
4
5
|
|
|
5
6
|
**Build AI agents in 15 lines. Ship to production.**
|
|
6
7
|
|
|
@@ -28,7 +29,7 @@ const app = new SvaraApp();
|
|
|
28
29
|
const agent = new SvaraAgent({
|
|
29
30
|
name: 'Support Bot',
|
|
30
31
|
model: 'gpt-4o-mini', // provider auto-detected
|
|
31
|
-
knowledge: './docs', // PDF, MD, TXT
|
|
32
|
+
knowledge: './docs', // PDF, MD, TXT, just point to a folder
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
app.route('/chat', agent.handler());
|
|
@@ -43,7 +44,7 @@ That's it. No pipeline setup. No embedding boilerplate. No webhook configuration
|
|
|
43
44
|
|
|
44
45
|
## Features
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
|||
|
|
47
48
|
|---|---|
|
|
48
49
|
| **Zero-config LLM** | Pass a model name, provider is auto-detected |
|
|
49
50
|
| **Instant RAG** | Point to a folder, documents are indexed automatically |
|
|
@@ -53,7 +54,7 @@ That's it. No pipeline setup. No embedding boilerplate. No webhook configuration
|
|
|
53
54
|
| **Express-compatible** | `agent.handler()` drops into any existing app |
|
|
54
55
|
| **Built-in database** | Persistent SQLite for users, sessions, RAG chunks, and state |
|
|
55
56
|
| **RAG per agent** | Each agent has isolated knowledge base, no cross-contamination |
|
|
56
|
-
| **RAG persistence** | Vector embeddings stored in SQLite,
|
|
57
|
+
| **RAG persistence** | Vector embeddings stored in SQLite, auto-dedup |
|
|
57
58
|
| **User tracking** | Auto-tracks users and sessions with timestamps |
|
|
58
59
|
| **CLI included** | `svara new`, `svara dev`, `svara build` |
|
|
59
60
|
|
|
@@ -262,6 +263,43 @@ await salesBot.start();
|
|
|
262
263
|
- Deduplication happens per agent (same content in different agents is OK)
|
|
263
264
|
- Perfect for multi-agent systems with different domains
|
|
264
265
|
|
|
266
|
+
**Accessing Retrieved Documents:**
|
|
267
|
+
|
|
268
|
+
The `/chat` endpoint returns `retrievedDocuments` showing which knowledge was used:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const response = await fetch('http://localhost:3000/chat', {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: { 'Content-Type': 'application/json' },
|
|
274
|
+
body: JSON.stringify({
|
|
275
|
+
message: 'What is the pricing?',
|
|
276
|
+
sessionId: 'user-123'
|
|
277
|
+
})
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const result = await response.json();
|
|
281
|
+
// {
|
|
282
|
+
// response: "Our pricing starts at...",
|
|
283
|
+
// retrievedDocuments: [
|
|
284
|
+
// {
|
|
285
|
+
// source: "./docs/pricing.md",
|
|
286
|
+
// score: 0.89, // relevance (0-1)
|
|
287
|
+
// excerpt: "# Pricing\n\nOur plans start at..."
|
|
288
|
+
// },
|
|
289
|
+
// {
|
|
290
|
+
// source: "./docs/faq.md",
|
|
291
|
+
// score: 0.76,
|
|
292
|
+
// excerpt: "## Is there a free trial?\n\nYes, 14 days..."
|
|
293
|
+
// }
|
|
294
|
+
// ]
|
|
295
|
+
// }
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The `retrievedDocuments` field shows:
|
|
299
|
+
- **source**: File path of the matching document
|
|
300
|
+
- **score**: Cosine similarity (0-1, higher = more relevant)
|
|
301
|
+
- **excerpt**: First 150 characters of the matched chunk
|
|
302
|
+
|
|
265
303
|
### User & Session Tracking
|
|
266
304
|
|
|
267
305
|
Every message automatically tracks the user and their session.
|
|
@@ -321,7 +359,7 @@ agent
|
|
|
321
359
|
verifyToken: process.env.WA_VERIFY_TOKEN,
|
|
322
360
|
});
|
|
323
361
|
|
|
324
|
-
await agent.start();
|
|
362
|
+
await agent.start(); // Start all channels
|
|
325
363
|
```
|
|
326
364
|
|
|
327
365
|
### Events
|
|
@@ -378,12 +416,15 @@ console.log(reply); // "It's currently 14:32 UTC..."
|
|
|
378
416
|
const agent = new SvaraAgent({
|
|
379
417
|
name: 'Support Bot',
|
|
380
418
|
model: 'gpt-4o-mini',
|
|
381
|
-
knowledge: './docs',
|
|
419
|
+
knowledge: './docs', // Auto-loaded on first request
|
|
382
420
|
systemPrompt: 'You are a customer support agent. Answer using the documentation.',
|
|
383
421
|
memory: { window: 20 },
|
|
384
422
|
});
|
|
385
423
|
|
|
386
|
-
|
|
424
|
+
const app = new SvaraApp({ cors: true });
|
|
425
|
+
app.route('/chat', agent.handler());
|
|
426
|
+
app.listen(3000);
|
|
427
|
+
// Knowledge indexes automatically on first request
|
|
387
428
|
```
|
|
388
429
|
|
|
389
430
|
### Multi-channel (Web + Telegram + WhatsApp)
|
|
@@ -424,21 +465,105 @@ app.listen(3000);
|
|
|
424
465
|
|
|
425
466
|
---
|
|
426
467
|
|
|
468
|
+
## Adding Knowledge & Tools at Runtime
|
|
469
|
+
|
|
470
|
+
### Adding knowledge (dynamic indexing)
|
|
471
|
+
|
|
472
|
+
After the agent is created, add more documents **without restarting**:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
const agent = new SvaraAgent({
|
|
476
|
+
name: 'Support Bot',
|
|
477
|
+
model: 'gpt-4o-mini',
|
|
478
|
+
knowledge: './docs', // Initial knowledge
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// ── Later (no restart needed) ──────────────────────
|
|
482
|
+
// Add a single document
|
|
483
|
+
await agent.addKnowledge('./policies/new-policy-2024.pdf');
|
|
484
|
+
|
|
485
|
+
// Add multiple documents
|
|
486
|
+
await agent.addKnowledge(['./faq.md', './terms.txt', './pricing.pdf']);
|
|
487
|
+
|
|
488
|
+
// Agent immediately has the new knowledge
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Real-world example** — admin endpoint to upload documents:
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
const app = new SvaraApp({ cors: true });
|
|
495
|
+
app.route('/chat', agent.handler());
|
|
496
|
+
|
|
497
|
+
// Admin: dynamically add knowledge
|
|
498
|
+
app.post('/admin/add-knowledge', async (req, res) => {
|
|
499
|
+
const { path } = req.body;
|
|
500
|
+
try {
|
|
501
|
+
await agent.addKnowledge(path);
|
|
502
|
+
res.json({ status: 'Knowledge added', path });
|
|
503
|
+
} catch (err) {
|
|
504
|
+
res.status(400).json({ error: (err as Error).message });
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
app.listen(3000);
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Adding tools (dynamic function calling)
|
|
512
|
+
|
|
513
|
+
Add tools at runtime with `addTool()`:
|
|
514
|
+
|
|
515
|
+
```ts
|
|
516
|
+
import { SvaraAgent, createTool } from '@yesvara/svara';
|
|
517
|
+
|
|
518
|
+
const agent = new SvaraAgent({
|
|
519
|
+
name: 'Assistant',
|
|
520
|
+
model: 'gpt-4o-mini',
|
|
521
|
+
tools: [initialTool], // Start with one tool
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// ── Later ────────────────────────────────────────
|
|
525
|
+
// Add more tools dynamically
|
|
526
|
+
const newTool = createTool({
|
|
527
|
+
name: 'send_email',
|
|
528
|
+
description: 'Send an email to a user',
|
|
529
|
+
parameters: {
|
|
530
|
+
to: { type: 'string', description: 'Email address', required: true },
|
|
531
|
+
subject: { type: 'string', description: 'Email subject', required: true },
|
|
532
|
+
body: { type: 'string', description: 'Email body', required: true },
|
|
533
|
+
},
|
|
534
|
+
async run({ to, subject, body }) {
|
|
535
|
+
// Call your email service
|
|
536
|
+
return { status: 'sent', to, subject };
|
|
537
|
+
},
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
agent.addTool(newTool);
|
|
541
|
+
|
|
542
|
+
// Agent can now use send_email tool
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Chainable tool registration** (multiple tools):
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
agent
|
|
549
|
+
.addTool(emailTool)
|
|
550
|
+
.addTool(databaseTool)
|
|
551
|
+
.addTool(slackTool)
|
|
552
|
+
.addTool(webhookTool);
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
427
557
|
## CLI
|
|
428
558
|
|
|
559
|
+
### Create a new project
|
|
560
|
+
|
|
429
561
|
```bash
|
|
430
|
-
# Scaffold a new project
|
|
431
562
|
svara new my-app
|
|
432
|
-
|
|
433
|
-
# Start dev server with hot-reload
|
|
434
|
-
svara dev
|
|
435
|
-
|
|
436
|
-
# Build for production
|
|
437
|
-
svara build
|
|
438
563
|
```
|
|
439
564
|
|
|
565
|
+
Output:
|
|
440
566
|
```
|
|
441
|
-
$ svara new my-app
|
|
442
567
|
✨ Creating SvaraJS project: my-app
|
|
443
568
|
|
|
444
569
|
✓ package.json
|
|
@@ -456,6 +581,89 @@ $ svara new my-app
|
|
|
456
581
|
npm run dev
|
|
457
582
|
```
|
|
458
583
|
|
|
584
|
+
Options:
|
|
585
|
+
- `--template <name>` — Use a specific template (default: `basic`)
|
|
586
|
+
- `basic` — Simple agent with HTTP endpoint
|
|
587
|
+
- `rag` — RAG-powered agent with document loader
|
|
588
|
+
- `multi-channel` — Web + Telegram + WhatsApp setup
|
|
589
|
+
- `tools` — Agent with tool calling examples
|
|
590
|
+
|
|
591
|
+
### Start development server
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
svara dev
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
Features:
|
|
598
|
+
- Hot-reload on file changes
|
|
599
|
+
- Auto-restart agent on code updates
|
|
600
|
+
- Debug logging enabled
|
|
601
|
+
- Serves on `http://localhost:3000` (configurable)
|
|
602
|
+
|
|
603
|
+
Options:
|
|
604
|
+
- `--port <number>` — Custom port (default: `3000`)
|
|
605
|
+
- `--watch <glob>` — Watch additional paths (default: `src/**`)
|
|
606
|
+
- `--env <file>` — Load custom .env file
|
|
607
|
+
|
|
608
|
+
### Build for production
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
svara build
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Outputs:
|
|
615
|
+
- `dist/` — Compiled JavaScript
|
|
616
|
+
- `dist/index.js` — Entry point (ready for Node or Docker)
|
|
617
|
+
- Source maps and type declarations included
|
|
618
|
+
|
|
619
|
+
Options:
|
|
620
|
+
- `--minify` — Minify output
|
|
621
|
+
- `--sourcemaps` — Include source maps (default: true)
|
|
622
|
+
- `--outdir <path>` — Custom output directory (default: `dist/`)
|
|
623
|
+
|
|
624
|
+
### Running built projects
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
# After building
|
|
628
|
+
node dist/index.js
|
|
629
|
+
|
|
630
|
+
# Or with env file
|
|
631
|
+
NODE_ENV=production OPENAI_API_KEY=sk-... node dist/index.js
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Database management
|
|
635
|
+
|
|
636
|
+
```bash
|
|
637
|
+
# Initialize database (auto-creates tables)
|
|
638
|
+
svara db init
|
|
639
|
+
|
|
640
|
+
# Show database schema
|
|
641
|
+
svara db schema
|
|
642
|
+
|
|
643
|
+
# Export users and conversation history
|
|
644
|
+
svara db export --format json
|
|
645
|
+
svara db export --format csv --table svara_messages
|
|
646
|
+
|
|
647
|
+
# Query database directly
|
|
648
|
+
svara db query "SELECT COUNT(*) FROM svara_users"
|
|
649
|
+
|
|
650
|
+
# Reset database (⚠️ deletes all data)
|
|
651
|
+
svara db reset
|
|
652
|
+
|
|
653
|
+
# Backup database
|
|
654
|
+
svara db backup --output backup-2026-01-15.db
|
|
655
|
+
|
|
656
|
+
# Restore from backup
|
|
657
|
+
svara db restore --input backup-2026-01-15.db
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Options:
|
|
661
|
+
- `--db <path>` — Custom database path (default: `./data/svara.db`)
|
|
662
|
+
- `--format <type>` — Export format: `json`, `csv`, `sql` (default: `json`)
|
|
663
|
+
- `--table <name>` — Specific table to export
|
|
664
|
+
- `--output <path>` — Output file path
|
|
665
|
+
- `--force` — Skip confirmation prompts (use with `reset` carefully!)
|
|
666
|
+
|
|
459
667
|
---
|
|
460
668
|
|
|
461
669
|
## Built-in Database
|
package/SvaraJS.png
ADDED
|
Binary file
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SvaraDB
|
|
3
|
+
} from "./chunk-GA7LHPOF.mjs";
|
|
1
4
|
import {
|
|
2
5
|
__require
|
|
3
6
|
} from "./chunk-CIESM3BP.mjs";
|
|
@@ -256,256 +259,6 @@ var Chunker = class {
|
|
|
256
259
|
}
|
|
257
260
|
};
|
|
258
261
|
|
|
259
|
-
// src/database/sqlite.ts
|
|
260
|
-
import path2 from "path";
|
|
261
|
-
import fs2 from "fs";
|
|
262
|
-
|
|
263
|
-
// src/database/schema.ts
|
|
264
|
-
var SCHEMA_VERSION = 1;
|
|
265
|
-
var CREATE_TABLES_SQL = `
|
|
266
|
-
-- Schema version tracking
|
|
267
|
-
CREATE TABLE IF NOT EXISTS svara_meta (
|
|
268
|
-
key TEXT PRIMARY KEY,
|
|
269
|
-
value TEXT NOT NULL
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
-- Conversation history persistence
|
|
273
|
-
CREATE TABLE IF NOT EXISTS svara_messages (
|
|
274
|
-
id TEXT PRIMARY KEY,
|
|
275
|
-
session_id TEXT NOT NULL,
|
|
276
|
-
role TEXT NOT NULL CHECK(role IN ('user', 'assistant', 'system', 'tool')),
|
|
277
|
-
content TEXT NOT NULL,
|
|
278
|
-
tool_call_id TEXT,
|
|
279
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
CREATE INDEX IF NOT EXISTS idx_messages_session
|
|
283
|
-
ON svara_messages (session_id, created_at);
|
|
284
|
-
|
|
285
|
-
-- User registry
|
|
286
|
-
CREATE TABLE IF NOT EXISTS svara_users (
|
|
287
|
-
id TEXT PRIMARY KEY,
|
|
288
|
-
email TEXT,
|
|
289
|
-
display_name TEXT,
|
|
290
|
-
first_seen INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
291
|
-
last_seen INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
292
|
-
metadata TEXT DEFAULT '{}'
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
CREATE INDEX IF NOT EXISTS idx_users_email
|
|
296
|
-
ON svara_users (email);
|
|
297
|
-
|
|
298
|
-
-- Session metadata
|
|
299
|
-
CREATE TABLE IF NOT EXISTS svara_sessions (
|
|
300
|
-
id TEXT PRIMARY KEY,
|
|
301
|
-
user_id TEXT NOT NULL,
|
|
302
|
-
channel TEXT NOT NULL,
|
|
303
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
304
|
-
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
305
|
-
metadata TEXT DEFAULT '{}',
|
|
306
|
-
FOREIGN KEY (user_id) REFERENCES svara_users(id)
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_user
|
|
310
|
-
ON svara_sessions (user_id);
|
|
311
|
-
|
|
312
|
-
-- Vector store chunks for RAG (per agent)
|
|
313
|
-
CREATE TABLE IF NOT EXISTS svara_chunks (
|
|
314
|
-
id TEXT PRIMARY KEY,
|
|
315
|
-
agent_name TEXT NOT NULL, -- Separate RAG per agent
|
|
316
|
-
document_id TEXT NOT NULL,
|
|
317
|
-
content TEXT NOT NULL,
|
|
318
|
-
content_hash TEXT NOT NULL, -- MD5 hash of content for deduplication
|
|
319
|
-
chunk_index INTEGER NOT NULL,
|
|
320
|
-
embedding TEXT, -- stored as JSON string of float array
|
|
321
|
-
source TEXT NOT NULL,
|
|
322
|
-
metadata TEXT DEFAULT '{}',
|
|
323
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_agent
|
|
327
|
-
ON svara_chunks (agent_name);
|
|
328
|
-
|
|
329
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_agent_document
|
|
330
|
-
ON svara_chunks (agent_name, document_id);
|
|
331
|
-
|
|
332
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_content_hash
|
|
333
|
-
ON svara_chunks (content_hash);
|
|
334
|
-
|
|
335
|
-
-- Document registry
|
|
336
|
-
CREATE TABLE IF NOT EXISTS svara_documents (
|
|
337
|
-
id TEXT PRIMARY KEY,
|
|
338
|
-
source TEXT NOT NULL UNIQUE,
|
|
339
|
-
type TEXT NOT NULL,
|
|
340
|
-
size INTEGER,
|
|
341
|
-
hash TEXT,
|
|
342
|
-
indexed_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
343
|
-
metadata TEXT DEFAULT '{}'
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
-- Key-value store for arbitrary agent state
|
|
347
|
-
CREATE TABLE IF NOT EXISTS svara_kv (
|
|
348
|
-
key TEXT PRIMARY KEY,
|
|
349
|
-
value TEXT NOT NULL,
|
|
350
|
-
expires_at INTEGER, -- unix timestamp, NULL = no expiry
|
|
351
|
-
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
352
|
-
);
|
|
353
|
-
`;
|
|
354
|
-
var INSERT_META_SQL = `
|
|
355
|
-
INSERT OR REPLACE INTO svara_meta (key, value)
|
|
356
|
-
VALUES ('schema_version', ?), ('created_at', ?);
|
|
357
|
-
`;
|
|
358
|
-
|
|
359
|
-
// src/database/sqlite.ts
|
|
360
|
-
var KVStore = class {
|
|
361
|
-
constructor(db) {
|
|
362
|
-
this.db = db;
|
|
363
|
-
}
|
|
364
|
-
db;
|
|
365
|
-
/** Set a key-value pair, with optional TTL in seconds. */
|
|
366
|
-
set(key, value, ttlSeconds) {
|
|
367
|
-
const expiresAt = ttlSeconds ? Math.floor(Date.now() / 1e3) + ttlSeconds : null;
|
|
368
|
-
this.db.prepare(`
|
|
369
|
-
INSERT OR REPLACE INTO svara_kv (key, value, expires_at, updated_at)
|
|
370
|
-
VALUES (?, ?, ?, unixepoch())
|
|
371
|
-
`).run(key, JSON.stringify(value), expiresAt);
|
|
372
|
-
}
|
|
373
|
-
/** Get a value by key. Returns undefined if not found or expired. */
|
|
374
|
-
get(key) {
|
|
375
|
-
const row = this.db.prepare(`
|
|
376
|
-
SELECT value, expires_at FROM svara_kv
|
|
377
|
-
WHERE key = ? AND (expires_at IS NULL OR expires_at > unixepoch())
|
|
378
|
-
`).get(key);
|
|
379
|
-
if (!row) return void 0;
|
|
380
|
-
return JSON.parse(row.value);
|
|
381
|
-
}
|
|
382
|
-
/** Delete a key. */
|
|
383
|
-
delete(key) {
|
|
384
|
-
this.db.prepare("DELETE FROM svara_kv WHERE key = ?").run(key);
|
|
385
|
-
}
|
|
386
|
-
/** Check if a key exists and is not expired. */
|
|
387
|
-
has(key) {
|
|
388
|
-
return this.get(key) !== void 0;
|
|
389
|
-
}
|
|
390
|
-
/** Get all keys matching a prefix. */
|
|
391
|
-
keys(prefix = "") {
|
|
392
|
-
const rows = this.db.prepare(`
|
|
393
|
-
SELECT key FROM svara_kv
|
|
394
|
-
WHERE key LIKE ? AND (expires_at IS NULL OR expires_at > unixepoch())
|
|
395
|
-
`).all(`${prefix}%`);
|
|
396
|
-
return rows.map((r) => r.key);
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
var SvaraDB = class {
|
|
400
|
-
db;
|
|
401
|
-
kv;
|
|
402
|
-
constructor(dbPath = ":memory:") {
|
|
403
|
-
if (dbPath !== ":memory:") {
|
|
404
|
-
fs2.mkdirSync(path2.dirname(path2.resolve(dbPath)), { recursive: true });
|
|
405
|
-
}
|
|
406
|
-
this.db = this.openDatabase(dbPath);
|
|
407
|
-
this.configure();
|
|
408
|
-
this.migrate();
|
|
409
|
-
this.kv = new KVStore(this.db);
|
|
410
|
-
}
|
|
411
|
-
// ─── Query Helpers ────────────────────────────────────────────────────────
|
|
412
|
-
/**
|
|
413
|
-
* Run a SELECT and return all matching rows.
|
|
414
|
-
*/
|
|
415
|
-
query(sql, params = []) {
|
|
416
|
-
return this.db.prepare(sql).all(...params);
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Run a SELECT and return the first matching row.
|
|
420
|
-
*/
|
|
421
|
-
queryOne(sql, params = []) {
|
|
422
|
-
return this.db.prepare(sql).get(...params);
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Run an INSERT/UPDATE/DELETE. Returns affected row count.
|
|
426
|
-
*/
|
|
427
|
-
run(sql, params = []) {
|
|
428
|
-
return this.db.prepare(sql).run(...params).changes;
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Execute raw SQL (for DDL, migrations, etc.).
|
|
432
|
-
*/
|
|
433
|
-
exec(sql) {
|
|
434
|
-
this.db.exec(sql);
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Run multiple operations in a single transaction.
|
|
438
|
-
*
|
|
439
|
-
* @example
|
|
440
|
-
* db.transaction(() => {
|
|
441
|
-
* db.run('INSERT INTO orders ...', [...]);
|
|
442
|
-
* db.run('UPDATE inventory ...', [...]);
|
|
443
|
-
* });
|
|
444
|
-
*/
|
|
445
|
-
transaction(fn) {
|
|
446
|
-
return this.db.transaction(fn)();
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Close the database connection.
|
|
450
|
-
*/
|
|
451
|
-
close() {
|
|
452
|
-
this.db.close();
|
|
453
|
-
}
|
|
454
|
-
// ─── Internal Message Storage ─────────────────────────────────────────────
|
|
455
|
-
saveMessage(params) {
|
|
456
|
-
this.db.prepare(`
|
|
457
|
-
INSERT OR REPLACE INTO svara_messages (id, session_id, role, content, tool_call_id)
|
|
458
|
-
VALUES (?, ?, ?, ?, ?)
|
|
459
|
-
`).run(
|
|
460
|
-
params.id,
|
|
461
|
-
params.sessionId,
|
|
462
|
-
params.role,
|
|
463
|
-
params.content,
|
|
464
|
-
params.toolCallId ?? null
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
getMessages(sessionId, limit = 50) {
|
|
468
|
-
return this.db.prepare(`
|
|
469
|
-
SELECT id, role, content, tool_call_id, created_at
|
|
470
|
-
FROM svara_messages
|
|
471
|
-
WHERE session_id = ?
|
|
472
|
-
ORDER BY created_at ASC
|
|
473
|
-
LIMIT ?
|
|
474
|
-
`).all(sessionId, limit);
|
|
475
|
-
}
|
|
476
|
-
clearSession(sessionId) {
|
|
477
|
-
this.db.prepare("DELETE FROM svara_messages WHERE session_id = ?").run(sessionId);
|
|
478
|
-
}
|
|
479
|
-
// ─── Private Setup ────────────────────────────────────────────────────────
|
|
480
|
-
openDatabase(dbPath) {
|
|
481
|
-
try {
|
|
482
|
-
const Database = __require("better-sqlite3");
|
|
483
|
-
return new Database(dbPath);
|
|
484
|
-
} catch {
|
|
485
|
-
throw new Error(
|
|
486
|
-
'[SvaraJS] Database requires the "better-sqlite3" package.\nRun: npm install better-sqlite3'
|
|
487
|
-
);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
configure() {
|
|
491
|
-
this.db.pragma("journal_mode = WAL");
|
|
492
|
-
this.db.pragma("synchronous = NORMAL");
|
|
493
|
-
this.db.pragma("foreign_keys = ON");
|
|
494
|
-
}
|
|
495
|
-
migrate() {
|
|
496
|
-
this.db.exec(CREATE_TABLES_SQL);
|
|
497
|
-
const meta = this.db.prepare(
|
|
498
|
-
"SELECT value FROM svara_meta WHERE key = 'schema_version'"
|
|
499
|
-
).get();
|
|
500
|
-
if (!meta) {
|
|
501
|
-
this.db.prepare(INSERT_META_SQL).run(
|
|
502
|
-
String(SCHEMA_VERSION),
|
|
503
|
-
(/* @__PURE__ */ new Date()).toISOString()
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
|
|
509
262
|
// src/rag/retriever.ts
|
|
510
263
|
import crypto3 from "crypto";
|
|
511
264
|
var OpenAIEmbeddings = class {
|
|
@@ -740,7 +493,6 @@ function cosineSimilarity(a, b) {
|
|
|
740
493
|
}
|
|
741
494
|
|
|
742
495
|
export {
|
|
743
|
-
SvaraDB,
|
|
744
496
|
DocumentLoader,
|
|
745
497
|
Chunker,
|
|
746
498
|
VectorRetriever
|