@yesvara/svara 0.1.0

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +497 -0
  3. package/dist/chunk-CIESM3BP.mjs +33 -0
  4. package/dist/chunk-FEA5KIJN.mjs +418 -0
  5. package/dist/cli/index.d.mts +1 -0
  6. package/dist/cli/index.d.ts +1 -0
  7. package/dist/cli/index.js +328 -0
  8. package/dist/cli/index.mjs +39 -0
  9. package/dist/dev-OYGXXK2B.mjs +69 -0
  10. package/dist/index.d.mts +967 -0
  11. package/dist/index.d.ts +967 -0
  12. package/dist/index.js +1976 -0
  13. package/dist/index.mjs +1502 -0
  14. package/dist/new-7K4NIDZO.mjs +177 -0
  15. package/dist/retriever-4QY667XF.mjs +7 -0
  16. package/examples/01-basic/index.ts +26 -0
  17. package/examples/02-with-tools/index.ts +73 -0
  18. package/examples/03-rag-knowledge/index.ts +41 -0
  19. package/examples/04-multi-channel/index.ts +91 -0
  20. package/package.json +74 -0
  21. package/src/app/index.ts +176 -0
  22. package/src/channels/telegram.ts +122 -0
  23. package/src/channels/web.ts +118 -0
  24. package/src/channels/whatsapp.ts +161 -0
  25. package/src/cli/commands/dev.ts +87 -0
  26. package/src/cli/commands/new.ts +213 -0
  27. package/src/cli/index.ts +78 -0
  28. package/src/core/agent.ts +607 -0
  29. package/src/core/llm.ts +406 -0
  30. package/src/core/types.ts +183 -0
  31. package/src/database/schema.ts +79 -0
  32. package/src/database/sqlite.ts +239 -0
  33. package/src/index.ts +94 -0
  34. package/src/memory/context.ts +49 -0
  35. package/src/memory/conversation.ts +51 -0
  36. package/src/rag/chunker.ts +165 -0
  37. package/src/rag/loader.ts +216 -0
  38. package/src/rag/retriever.ts +248 -0
  39. package/src/tools/executor.ts +54 -0
  40. package/src/tools/index.ts +89 -0
  41. package/src/tools/registry.ts +44 -0
  42. package/src/types.ts +131 -0
  43. package/tsconfig.json +26 -0
@@ -0,0 +1,967 @@
1
+ import { RequestHandler, Express } from 'express';
2
+ import EventEmitter from 'events';
3
+
4
+ /**
5
+ * @module SvaraApp
6
+ *
7
+ * The framework entry point. Wraps Express to give you a clean,
8
+ * AI-first HTTP server that works with zero configuration.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { SvaraApp, SvaraAgent } from '@yesvara/svara';
13
+ *
14
+ * const app = new SvaraApp();
15
+ *
16
+ * const agent = new SvaraAgent({
17
+ * name: 'Support Bot',
18
+ * model: 'gpt-4o-mini',
19
+ * knowledge: './docs',
20
+ * });
21
+ *
22
+ * app.route('/chat', agent.handler());
23
+ * app.listen(3000);
24
+ * // → Server running at http://localhost:3000
25
+ * // → POST /chat accepts { message, sessionId }
26
+ * // → GET /health returns { status: 'ok' }
27
+ * ```
28
+ *
29
+ * @example With your own Express app
30
+ * ```ts
31
+ * import express from 'express';
32
+ * const expressApp = express();
33
+ *
34
+ * // Mount as middleware on any path
35
+ * expressApp.post('/api/chat', agent.handler());
36
+ * ```
37
+ */
38
+
39
+ interface AppOptions {
40
+ /**
41
+ * Enable CORS. Pass `true` for wildcard (*), or a specific origin string.
42
+ * @default false
43
+ */
44
+ cors?: boolean | string;
45
+ /**
46
+ * Require an API key in the `Authorization: Bearer <key>` header.
47
+ * Useful for protecting your agent endpoint.
48
+ */
49
+ apiKey?: string;
50
+ /**
51
+ * Request body size limit. @default '10mb'
52
+ */
53
+ bodyLimit?: string;
54
+ }
55
+ declare class SvaraApp {
56
+ private readonly express;
57
+ private server;
58
+ constructor(options?: AppOptions);
59
+ /**
60
+ * Mount an agent (or any Express handler) on a route.
61
+ * Returns `this` for chaining.
62
+ *
63
+ * @example
64
+ * app
65
+ * .route('/chat', supportAgent.handler())
66
+ * .route('/sales', salesAgent.handler());
67
+ */
68
+ route(path: string, handler: RequestHandler): this;
69
+ /**
70
+ * Add Express middleware (logging, auth, rate limiting, etc.)
71
+ *
72
+ * @example
73
+ * import rateLimit from 'express-rate-limit';
74
+ * app.use(rateLimit({ windowMs: 60_000, max: 100 }));
75
+ */
76
+ use(middleware: RequestHandler): this;
77
+ /**
78
+ * Start listening on the given port.
79
+ *
80
+ * @example
81
+ * await app.listen(3000);
82
+ * // → [@yesvara/svara] Listening at http://localhost:3000
83
+ */
84
+ listen(port?: number): Promise<void>;
85
+ /**
86
+ * Stop the server gracefully.
87
+ */
88
+ stop(): Promise<void>;
89
+ /**
90
+ * Access the underlying Express app for advanced configuration.
91
+ *
92
+ * @example
93
+ * const expressApp = app.express();
94
+ * expressApp.set('trust proxy', 1);
95
+ */
96
+ getExpressApp(): Express;
97
+ private setup;
98
+ }
99
+
100
+ /**
101
+ * @internal
102
+ * Internal types for the SvaraJS framework engine.
103
+ * These are NOT exported to users — see src/types.ts for the public API.
104
+ */
105
+ type LLMProviderName = 'openai' | 'anthropic' | 'ollama' | 'groq';
106
+ interface LLMConfig {
107
+ provider: LLMProviderName;
108
+ model: string;
109
+ apiKey?: string;
110
+ baseURL?: string;
111
+ temperature?: number;
112
+ maxTokens?: number;
113
+ timeout?: number;
114
+ }
115
+ interface LLMMessage {
116
+ role: 'system' | 'user' | 'assistant' | 'tool';
117
+ content: string;
118
+ toolCallId?: string;
119
+ toolCalls?: LLMToolCall[];
120
+ name?: string;
121
+ }
122
+ interface LLMToolCall {
123
+ id: string;
124
+ name: string;
125
+ arguments: Record<string, unknown>;
126
+ }
127
+ interface TokenUsage {
128
+ promptTokens: number;
129
+ completionTokens: number;
130
+ totalTokens: number;
131
+ }
132
+ interface InternalAgentContext {
133
+ sessionId: string;
134
+ userId: string;
135
+ agentName: string;
136
+ history: LLMMessage[];
137
+ metadata: Record<string, unknown>;
138
+ }
139
+ interface AgentRunOptions {
140
+ sessionId?: string;
141
+ userId?: string;
142
+ metadata?: Record<string, unknown>;
143
+ }
144
+ interface AgentRunResult {
145
+ response: string;
146
+ sessionId: string;
147
+ toolsUsed: string[];
148
+ iterations: number;
149
+ usage: TokenUsage;
150
+ duration: number;
151
+ }
152
+ type DocumentType = 'text' | 'markdown' | 'pdf' | 'html' | 'json' | 'docx';
153
+ interface Document {
154
+ id: string;
155
+ content: string;
156
+ type: DocumentType;
157
+ source: string;
158
+ metadata: {
159
+ filename: string;
160
+ extension: string;
161
+ size: number;
162
+ lastModified: string;
163
+ };
164
+ }
165
+ interface DocumentChunk {
166
+ id: string;
167
+ documentId: string;
168
+ content: string;
169
+ index: number;
170
+ metadata: {
171
+ filename: string;
172
+ extension: string;
173
+ size: number;
174
+ lastModified: string;
175
+ chunkIndex: number;
176
+ strategy: 'fixed' | 'sentence' | 'paragraph';
177
+ charCount: number;
178
+ };
179
+ }
180
+ interface RAGConfig {
181
+ embeddings?: {
182
+ provider: 'openai' | 'ollama';
183
+ apiKey?: string;
184
+ model?: string;
185
+ };
186
+ chunking?: {
187
+ strategy?: 'fixed' | 'sentence' | 'paragraph';
188
+ size?: number;
189
+ overlap?: number;
190
+ };
191
+ retrieval?: {
192
+ threshold?: number;
193
+ };
194
+ }
195
+ interface RetrievedContext {
196
+ chunks: DocumentChunk[];
197
+ query: string;
198
+ totalFound: number;
199
+ }
200
+ interface RAGRetriever {
201
+ init(config: RAGConfig): Promise<void>;
202
+ addDocuments(filePaths: string[]): Promise<void>;
203
+ retrieve(query: string, topK?: number): Promise<string>;
204
+ retrieveChunks(query: string, topK?: number): Promise<RetrievedContext>;
205
+ }
206
+ type ChannelName = 'web' | 'whatsapp' | 'telegram' | 'discord' | 'slack';
207
+ interface IncomingMessage {
208
+ id: string;
209
+ sessionId: string;
210
+ userId: string;
211
+ channel: ChannelName;
212
+ text: string;
213
+ timestamp: Date;
214
+ raw?: unknown;
215
+ }
216
+
217
+ /**
218
+ * @module types
219
+ * Public types for @yesvara/svara
220
+ *
221
+ * These are the types users import and work with directly.
222
+ * Internal implementation types stay in core/types.ts.
223
+ */
224
+
225
+ /**
226
+ * A function the agent can call during a conversation.
227
+ *
228
+ * @example
229
+ * const weatherTool: Tool = {
230
+ * name: 'get_weather',
231
+ * description: 'Get the current weather for a city',
232
+ * parameters: {
233
+ * city: { type: 'string', description: 'The city name', required: true },
234
+ * },
235
+ * async run({ city }) {
236
+ * const data = await fetchWeather(city as string);
237
+ * return { temp: data.temp, condition: data.condition };
238
+ * },
239
+ * };
240
+ */
241
+ interface Tool {
242
+ /** Unique identifier used by the LLM to call this tool. snake_case recommended. */
243
+ name: string;
244
+ /** What this tool does. The LLM uses this to decide when to call it. Be specific. */
245
+ description: string;
246
+ /**
247
+ * Input parameters the tool accepts.
248
+ * The LLM will fill these in based on the conversation.
249
+ */
250
+ parameters?: Record<string, ToolParameter>;
251
+ /**
252
+ * The function that runs when the LLM calls this tool.
253
+ * Return anything — it gets serialized and sent back to the LLM.
254
+ */
255
+ run(args: Record<string, unknown>, ctx: AgentContext): Promise<unknown>;
256
+ /** Group related tools together. Optional — used for organization. */
257
+ category?: string;
258
+ /** Timeout in milliseconds before the tool is cancelled. @default 30000 */
259
+ timeout?: number;
260
+ }
261
+ /**
262
+ * A single parameter definition for a tool.
263
+ *
264
+ * @example
265
+ * { type: 'string', description: 'City name', required: true }
266
+ * { type: 'number', description: 'Temperature in Celsius', required: false }
267
+ * { type: 'string', description: 'Status', enum: ['active', 'inactive'] }
268
+ */
269
+ interface ToolParameter {
270
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
271
+ description: string;
272
+ required?: boolean;
273
+ enum?: string[];
274
+ default?: unknown;
275
+ }
276
+ /**
277
+ * Context passed to tool `run()` functions.
278
+ * Gives tools access to session info and conversation history.
279
+ */
280
+ type AgentContext = InternalAgentContext;
281
+ /**
282
+ * The full result of a `agent.process()` call.
283
+ */
284
+ interface ProcessResult {
285
+ /** The agent's response text. */
286
+ response: string;
287
+ /** The session ID used for this conversation. */
288
+ sessionId: string;
289
+ /** Names of tools called during this response. */
290
+ toolsUsed: string[];
291
+ /** Number of LLM iterations (tool call rounds) used. */
292
+ iterations: number;
293
+ /** Token usage for this request. */
294
+ usage: {
295
+ promptTokens: number;
296
+ completionTokens: number;
297
+ totalTokens: number;
298
+ };
299
+ /** Total time in milliseconds. */
300
+ duration: number;
301
+ }
302
+ /**
303
+ * Memory configuration for a SvaraAgent.
304
+ */
305
+ interface MemoryOptions {
306
+ /** Number of previous messages to include in context. @default 20 */
307
+ window?: number;
308
+ }
309
+
310
+ /**
311
+ * @module SvaraAgent
312
+ *
313
+ * The heart of the framework. One class. Infinite possibilities.
314
+ *
315
+ * A SvaraAgent is a stateful AI agent that:
316
+ * - Holds a conversation across multiple turns (memory)
317
+ * - Can search your documents to answer questions (RAG)
318
+ * - Can call functions you define (tools)
319
+ * - Can receive messages from any channel (WhatsApp, Telegram, Web, etc.)
320
+ *
321
+ * @example Minimal — works in 5 lines
322
+ * ```ts
323
+ * const agent = new SvaraAgent({ name: 'Aria', model: 'gpt-4o' });
324
+ * const reply = await agent.chat('What is the capital of France?');
325
+ * console.log(reply); // "Paris"
326
+ * ```
327
+ *
328
+ * @example Full — production-ready bot
329
+ * ```ts
330
+ * const agent = new SvaraAgent({
331
+ * name: 'Support Bot',
332
+ * model: 'gpt-4o-mini',
333
+ * systemPrompt: 'You are a helpful support agent.',
334
+ * knowledge: './docs',
335
+ * memory: { window: 20 },
336
+ * });
337
+ *
338
+ * agent
339
+ * .addTool(emailTool)
340
+ * .addTool(databaseTool)
341
+ * .connectChannel('telegram', { token: process.env.TG_TOKEN });
342
+ *
343
+ * await agent.start();
344
+ * ```
345
+ */
346
+
347
+ interface SvaraChannel {
348
+ readonly name: ChannelName;
349
+ mount(agent: SvaraAgent): Promise<void>;
350
+ send(sessionId: string, text: string): Promise<void>;
351
+ stop(): Promise<void>;
352
+ }
353
+ interface AgentConfig {
354
+ /**
355
+ * Display name for this agent.
356
+ * Used in logs, system prompts, and the CLI.
357
+ */
358
+ name: string;
359
+ /**
360
+ * LLM model to use. Provider is auto-detected from the name.
361
+ *
362
+ * @example 'gpt-4o' — OpenAI (needs OPENAI_API_KEY)
363
+ * @example 'claude-opus-4-6' — Anthropic (needs ANTHROPIC_API_KEY)
364
+ * @example 'llama3' — Ollama (local, needs Ollama running)
365
+ * @example 'gpt-4o-mini' — OpenAI (cheaper, faster)
366
+ */
367
+ model: string;
368
+ /**
369
+ * Instruction that shapes the agent's personality and behavior.
370
+ * If omitted, a sensible default is used based on `name`.
371
+ */
372
+ systemPrompt?: string;
373
+ /**
374
+ * Path(s) to your documents for RAG (Retrieval Augmented Generation).
375
+ * Supports PDF, Markdown, TXT, DOCX, HTML, JSON. Glob patterns welcome.
376
+ *
377
+ * @example './docs'
378
+ * @example ['./faqs.pdf', './policies/*.md']
379
+ */
380
+ knowledge?: string | string[];
381
+ /**
382
+ * Conversation memory configuration.
383
+ * - `true` — enable with defaults (20 message window)
384
+ * - `false` — disable (stateless, every call is fresh)
385
+ * - object — custom configuration
386
+ *
387
+ * @default true
388
+ */
389
+ memory?: boolean | {
390
+ window?: number;
391
+ };
392
+ /**
393
+ * Tools (function calls) the agent can use.
394
+ * Can also add tools later with `agent.addTool()`.
395
+ */
396
+ tools?: Tool[];
397
+ /**
398
+ * LLM temperature — controls creativity vs. precision.
399
+ * 0 = deterministic, 2 = very creative. Default: 0.7
400
+ */
401
+ temperature?: number;
402
+ /**
403
+ * Max output tokens per LLM call. Default: provider-dependent.
404
+ */
405
+ maxTokens?: number;
406
+ /**
407
+ * Maximum agentic loop iterations (tool calls) per message.
408
+ * Prevents infinite loops. Default: 10
409
+ */
410
+ maxIterations?: number;
411
+ /**
412
+ * Advanced: override LLM provider or add custom endpoint.
413
+ * Usually not needed — `model` auto-detects the provider.
414
+ */
415
+ llm?: Partial<LLMConfig>;
416
+ /**
417
+ * Print detailed logs of every LLM call, tool execution, and memory operation.
418
+ * Useful during development. Default: false
419
+ */
420
+ verbose?: boolean;
421
+ }
422
+ declare class SvaraAgent extends EventEmitter {
423
+ readonly name: string;
424
+ private readonly llmConfig;
425
+ private readonly llm;
426
+ private readonly systemPrompt;
427
+ private readonly tools;
428
+ private readonly executor;
429
+ private readonly memory;
430
+ private readonly context;
431
+ private readonly maxIterations;
432
+ private readonly verbose;
433
+ private channels;
434
+ private knowledgeBase;
435
+ private knowledgePaths;
436
+ private isStarted;
437
+ constructor(config: AgentConfig);
438
+ /**
439
+ * Send a message and get a reply. The simplest way to use an agent.
440
+ *
441
+ * @example
442
+ * const reply = await agent.chat('What is the weather in Tokyo?');
443
+ * console.log(reply); // "Currently 28°C and sunny in Tokyo."
444
+ *
445
+ * @param message The user's message.
446
+ * @param sessionId Optional session ID for multi-turn conversations.
447
+ * Defaults to 'default' — all calls share one history.
448
+ */
449
+ chat(message: string, sessionId?: string): Promise<string>;
450
+ /**
451
+ * Process a message and get the full result with metadata.
452
+ * Use this when you need usage stats, tool info, or session details.
453
+ *
454
+ * @example
455
+ * const result = await agent.process('Summarize my report', {
456
+ * sessionId: 'user-42',
457
+ * userId: 'alice@example.com',
458
+ * });
459
+ * console.log(result.response); // The agent's reply
460
+ * console.log(result.toolsUsed); // ['read_file', 'summarize']
461
+ * console.log(result.usage); // { totalTokens: 1234, ... }
462
+ */
463
+ process(message: string, options?: AgentRunOptions): Promise<AgentRunResult>;
464
+ /**
465
+ * Register a tool the agent can call during a conversation.
466
+ * Returns `this` for chaining.
467
+ *
468
+ * @example
469
+ * agent
470
+ * .addTool(weatherTool)
471
+ * .addTool(emailTool)
472
+ * .addTool(databaseTool);
473
+ */
474
+ addTool(tool: Tool): this;
475
+ /**
476
+ * Connect a messaging channel. The agent will receive and respond to
477
+ * messages from this channel automatically.
478
+ *
479
+ * @example
480
+ * agent.connectChannel('telegram', { token: process.env.TG_TOKEN });
481
+ * agent.connectChannel('whatsapp', {
482
+ * token: process.env.WA_TOKEN,
483
+ * phoneId: process.env.WA_PHONE_ID,
484
+ * verifyToken: process.env.WA_VERIFY_TOKEN,
485
+ * });
486
+ */
487
+ connectChannel(name: ChannelName, config: Record<string, unknown>): this;
488
+ /**
489
+ * Returns an Express request handler for mounting on any HTTP server.
490
+ * POST body: `{ message: string, sessionId?: string, userId?: string }`
491
+ *
492
+ * @example With SvaraApp
493
+ * app.route('/chat', agent.handler());
494
+ *
495
+ * @example With existing Express app
496
+ * expressApp.post('/api/chat', agent.handler());
497
+ */
498
+ handler(): RequestHandler;
499
+ /**
500
+ * Initialize all channels and knowledge base, then start listening.
501
+ * Call this once after you've configured the agent.
502
+ *
503
+ * @example
504
+ * agent.connectChannel('web', { port: 3000 });
505
+ * await agent.start(); // "Web channel running at http://localhost:3000"
506
+ */
507
+ start(): Promise<void>;
508
+ /**
509
+ * Gracefully shut down all channels.
510
+ */
511
+ stop(): Promise<void>;
512
+ /**
513
+ * Clear conversation history for a session.
514
+ *
515
+ * @example
516
+ * agent.on('user:leave', (userId) => agent.clearHistory(userId));
517
+ */
518
+ clearHistory(sessionId: string): Promise<void>;
519
+ /**
520
+ * Add documents to the knowledge base at runtime (no restart needed).
521
+ *
522
+ * @example
523
+ * agent.addKnowledge('./new-policies.pdf');
524
+ */
525
+ addKnowledge(paths: string | string[]): Promise<void>;
526
+ /**
527
+ * Receives a raw incoming message from a channel and processes it.
528
+ * Called by channel handlers — not typically used directly.
529
+ */
530
+ receive(msg: IncomingMessage): Promise<AgentRunResult>;
531
+ private run;
532
+ private initKnowledge;
533
+ private loadChannel;
534
+ private log;
535
+ }
536
+
537
+ /**
538
+ * @module tools
539
+ *
540
+ * `createTool` — the elegant way to define tools for your agent.
541
+ *
542
+ * @example
543
+ * ```ts
544
+ * import { createTool } from '@yesvara/svara';
545
+ *
546
+ * const weatherTool = createTool({
547
+ * name: 'get_weather',
548
+ * description: 'Get the current weather for a location',
549
+ * parameters: {
550
+ * city: { type: 'string', description: 'City name', required: true },
551
+ * units: { type: 'string', description: 'Temperature units', enum: ['celsius', 'fahrenheit'] },
552
+ * },
553
+ * async run({ city, units = 'celsius' }) {
554
+ * const data = await fetchWeather(city as string);
555
+ * return { temp: data.temp, condition: data.description, city };
556
+ * },
557
+ * });
558
+ *
559
+ * agent.addTool(weatherTool);
560
+ * ```
561
+ */
562
+
563
+ /**
564
+ * Create a type-safe tool definition with IDE autocomplete.
565
+ *
566
+ * This is a convenience wrapper — it validates your tool at definition time
567
+ * and returns a properly typed `Tool` object.
568
+ *
569
+ * @example Basic tool
570
+ * ```ts
571
+ * const timeTool = createTool({
572
+ * name: 'get_current_time',
573
+ * description: 'Get the current date and time',
574
+ * parameters: {},
575
+ * async run() {
576
+ * return { datetime: new Date().toISOString() };
577
+ * },
578
+ * });
579
+ * ```
580
+ *
581
+ * @example Tool with parameters and error handling
582
+ * ```ts
583
+ * const searchTool = createTool({
584
+ * name: 'search_database',
585
+ * description: 'Search for records in the database',
586
+ * parameters: {
587
+ * query: { type: 'string', description: 'Search query', required: true },
588
+ * limit: { type: 'number', description: 'Max results to return' },
589
+ * },
590
+ * async run({ query, limit = 10 }, ctx) {
591
+ * console.log(`[${ctx.agentName}] Searching for: ${query}`);
592
+ * const results = await db.search(String(query), Number(limit));
593
+ * return { results, count: results.length };
594
+ * },
595
+ * timeout: 10_000, // 10 seconds
596
+ * });
597
+ * ```
598
+ */
599
+ declare function createTool(definition: Tool): Tool;
600
+
601
+ /**
602
+ * @module database/sqlite
603
+ * SvaraJS — SQLite adapter
604
+ *
605
+ * A clean, ergonomic wrapper around better-sqlite3.
606
+ * Provides typed query helpers, migrations, and a KV store.
607
+ * Used internally by SvaraJS and optionally exposed to users.
608
+ *
609
+ * @example
610
+ * const db = new SvaraDB('./data/agent.db');
611
+ *
612
+ * // Typed queries
613
+ * const users = db.query<{ id: string; name: string }>(
614
+ * 'SELECT id, name FROM users WHERE active = ?', [1]
615
+ * );
616
+ *
617
+ * // KV store
618
+ * db.kv.set('onboarding:done', true);
619
+ * const done = db.kv.get<boolean>('onboarding:done');
620
+ *
621
+ * // Custom tables
622
+ * db.exec(`CREATE TABLE IF NOT EXISTS orders (id TEXT PRIMARY KEY, ...)`);
623
+ */
624
+ type Database = {
625
+ prepare: (sql: string) => Statement;
626
+ exec: (sql: string) => void;
627
+ close: () => void;
628
+ pragma: (pragma: string, options?: {
629
+ simple?: boolean;
630
+ }) => unknown;
631
+ transaction: <T>(fn: () => T) => () => T;
632
+ };
633
+ type Statement = {
634
+ run: (...args: unknown[]) => {
635
+ lastInsertRowid: bigint | number;
636
+ changes: number;
637
+ };
638
+ get: (...args: unknown[]) => unknown;
639
+ all: (...args: unknown[]) => unknown[];
640
+ };
641
+ declare class KVStore {
642
+ private db;
643
+ constructor(db: Database);
644
+ /** Set a key-value pair, with optional TTL in seconds. */
645
+ set<T>(key: string, value: T, ttlSeconds?: number): void;
646
+ /** Get a value by key. Returns undefined if not found or expired. */
647
+ get<T = unknown>(key: string): T | undefined;
648
+ /** Delete a key. */
649
+ delete(key: string): void;
650
+ /** Check if a key exists and is not expired. */
651
+ has(key: string): boolean;
652
+ /** Get all keys matching a prefix. */
653
+ keys(prefix?: string): string[];
654
+ }
655
+ declare class SvaraDB {
656
+ private db;
657
+ readonly kv: KVStore;
658
+ constructor(dbPath?: string);
659
+ /**
660
+ * Run a SELECT and return all matching rows.
661
+ */
662
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[];
663
+ /**
664
+ * Run a SELECT and return the first matching row.
665
+ */
666
+ queryOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): T | undefined;
667
+ /**
668
+ * Run an INSERT/UPDATE/DELETE. Returns affected row count.
669
+ */
670
+ run(sql: string, params?: unknown[]): number;
671
+ /**
672
+ * Execute raw SQL (for DDL, migrations, etc.).
673
+ */
674
+ exec(sql: string): void;
675
+ /**
676
+ * Run multiple operations in a single transaction.
677
+ *
678
+ * @example
679
+ * db.transaction(() => {
680
+ * db.run('INSERT INTO orders ...', [...]);
681
+ * db.run('UPDATE inventory ...', [...]);
682
+ * });
683
+ */
684
+ transaction<T>(fn: () => T): T;
685
+ /**
686
+ * Close the database connection.
687
+ */
688
+ close(): void;
689
+ saveMessage(params: {
690
+ id: string;
691
+ sessionId: string;
692
+ role: string;
693
+ content: string;
694
+ toolCallId?: string;
695
+ }): void;
696
+ getMessages(sessionId: string, limit?: number): Array<{
697
+ id: string;
698
+ role: string;
699
+ content: string;
700
+ tool_call_id: string | null;
701
+ created_at: number;
702
+ }>;
703
+ clearSession(sessionId: string): void;
704
+ private openDatabase;
705
+ private configure;
706
+ private migrate;
707
+ }
708
+
709
+ /**
710
+ * @module channels/web
711
+ *
712
+ * HTTP channel — exposes the agent as a REST API with SSE streaming.
713
+ *
714
+ * Used automatically when you call:
715
+ * ```ts
716
+ * agent.connectChannel('web', { port: 3000 });
717
+ * ```
718
+ *
719
+ * Or mount it on SvaraApp/Express:
720
+ * ```ts
721
+ * app.route('/chat', agent.handler());
722
+ * ```
723
+ *
724
+ * API:
725
+ * POST /chat — { message, sessionId? } → { response, sessionId, usage }
726
+ * GET /health — { status: 'ok' }
727
+ */
728
+
729
+ interface WebChannelConfig {
730
+ port?: number;
731
+ cors?: boolean | string;
732
+ apiKey?: string;
733
+ path?: string;
734
+ }
735
+ declare class WebChannel implements SvaraChannel {
736
+ private config;
737
+ readonly name: ChannelName;
738
+ private app;
739
+ private server;
740
+ private agent;
741
+ constructor(config?: WebChannelConfig);
742
+ mount(agent: SvaraAgent): Promise<void>;
743
+ send(_sessionId: string, _text: string): Promise<void>;
744
+ stop(): Promise<void>;
745
+ private buildApp;
746
+ private attachRoutes;
747
+ private buildMessage;
748
+ }
749
+
750
+ /**
751
+ * @module channels/telegram
752
+ *
753
+ * Telegram Bot channel.
754
+ * Used when you call: `agent.connectChannel('telegram', { token: '...' })`
755
+ */
756
+
757
+ interface TelegramChannelConfig {
758
+ token: string;
759
+ mode?: 'polling' | 'webhook';
760
+ webhookUrl?: string;
761
+ pollingInterval?: number;
762
+ }
763
+ declare class TelegramChannel implements SvaraChannel {
764
+ private config;
765
+ readonly name: ChannelName;
766
+ private agent;
767
+ private baseUrl;
768
+ private lastUpdateId;
769
+ private pollingTimer;
770
+ constructor(config: TelegramChannelConfig);
771
+ mount(agent: SvaraAgent): Promise<void>;
772
+ send(sessionId: string, text: string): Promise<void>;
773
+ stop(): Promise<void>;
774
+ private startPolling;
775
+ private handleUpdate;
776
+ private sendMessage;
777
+ private api;
778
+ private split;
779
+ }
780
+
781
+ /**
782
+ * @module channels/whatsapp
783
+ *
784
+ * WhatsApp Business API channel (Meta Cloud API).
785
+ * Used when you call: `agent.connectChannel('whatsapp', { ... })`
786
+ *
787
+ * Requires the 'web' channel to be mounted first (it shares the Express server).
788
+ * Webhook endpoint: POST /whatsapp/webhook
789
+ */
790
+
791
+ interface WhatsAppChannelConfig {
792
+ /** WhatsApp Cloud API access token */
793
+ token: string;
794
+ /** Your WhatsApp Phone Number ID */
795
+ phoneId: string;
796
+ /** Token to verify the webhook with Meta */
797
+ verifyToken: string;
798
+ /** API version, default 'v19.0' */
799
+ apiVersion?: string;
800
+ }
801
+ declare class WhatsAppChannel implements SvaraChannel {
802
+ private config;
803
+ readonly name: ChannelName;
804
+ private agent;
805
+ private readonly apiUrl;
806
+ constructor(config: WhatsAppChannelConfig);
807
+ mount(agent: SvaraAgent): Promise<void>;
808
+ send(to: string, text: string): Promise<void>;
809
+ stop(): Promise<void>;
810
+ private handle;
811
+ private sendMessage;
812
+ private split;
813
+ }
814
+
815
+ /**
816
+ * @module rag/loader
817
+ * SvaraJS — Document loader
818
+ *
819
+ * Loads documents from various sources into a normalized format.
820
+ * Supported formats: TXT, MD, PDF, DOCX, HTML, JSON
821
+ *
822
+ * @example
823
+ * const loader = new DocumentLoader();
824
+ * const docs = await loader.loadMany(['./docs/*.pdf', './knowledge/*.txt']);
825
+ */
826
+
827
+ declare class DocumentLoader {
828
+ private loaders;
829
+ private extensionMap;
830
+ constructor();
831
+ /**
832
+ * Load a single file into a Document.
833
+ */
834
+ load(filePath: string): Promise<Document>;
835
+ /**
836
+ * Load multiple files. Silently skips unreadable files with a warning.
837
+ */
838
+ loadMany(filePaths: string[]): Promise<Document[]>;
839
+ /** Check if this loader supports a given file extension. */
840
+ supports(filePath: string): boolean;
841
+ private detectType;
842
+ private hashFile;
843
+ }
844
+
845
+ /**
846
+ * @module rag/chunker
847
+ * SvaraJS — Document chunking strategies
848
+ *
849
+ * Breaks documents into retrieval-optimized chunks.
850
+ * Strategy selection matters: fixed for code/data, sentence for prose, paragraph for docs.
851
+ *
852
+ * @example
853
+ * const chunker = new Chunker({ strategy: 'sentence', size: 512, overlap: 50 });
854
+ * const chunks = chunker.chunk(document);
855
+ */
856
+
857
+ interface ChunkOptions {
858
+ strategy?: 'fixed' | 'sentence' | 'paragraph';
859
+ size?: number;
860
+ overlap?: number;
861
+ }
862
+ declare class Chunker {
863
+ private options;
864
+ constructor(options?: ChunkOptions);
865
+ /**
866
+ * Split a document into overlapping chunks.
867
+ * Returns the document with populated `chunks` field.
868
+ */
869
+ chunk(document: Document): DocumentChunk[];
870
+ /**
871
+ * Chunk multiple documents at once.
872
+ */
873
+ chunkMany(documents: Document[]): DocumentChunk[];
874
+ /** Split into fixed-size windows with overlap. Good for code and structured data. */
875
+ private fixedChunk;
876
+ /**
877
+ * Split by sentences, grouping them until size limit.
878
+ * Best for prose text — preserves natural reading units.
879
+ */
880
+ private sentenceChunk;
881
+ /**
882
+ * Split by paragraphs (double newline), grouping small ones.
883
+ * Best for documentation, articles, and manuals.
884
+ */
885
+ private paragraphChunk;
886
+ private splitSentences;
887
+ private groupBySize;
888
+ private chunkId;
889
+ }
890
+
891
+ /**
892
+ * @module rag/retriever
893
+ * SvaraJS — Vector retrieval for RAG
894
+ *
895
+ * Embeds document chunks and performs similarity search.
896
+ * Uses in-memory vector store by default (great for dev),
897
+ * with SQLite persistence for production.
898
+ *
899
+ * @example
900
+ * const retriever = new VectorRetriever();
901
+ * await retriever.init({ embeddings: { provider: 'openai' } });
902
+ * await retriever.addDocuments(['./docs/*.pdf']);
903
+ *
904
+ * const context = await retriever.retrieve('What is the refund policy?');
905
+ */
906
+
907
+ declare class VectorRetriever implements RAGRetriever {
908
+ private embedder;
909
+ private store;
910
+ private loader;
911
+ private chunker;
912
+ private config;
913
+ constructor();
914
+ init(config: RAGConfig): Promise<void>;
915
+ addDocuments(filePaths: string[]): Promise<void>;
916
+ retrieve(query: string, topK?: number): Promise<string>;
917
+ retrieveChunks(query: string, topK?: number): Promise<RetrievedContext>;
918
+ }
919
+
920
+ /**
921
+ * @yesvara/svara — Agentic AI Backend Framework
922
+ *
923
+ * Build production-ready AI agents in minutes, not months.
924
+ *
925
+ * @example The 15-line agent
926
+ * ```ts
927
+ * import { SvaraApp, SvaraAgent } from '@yesvara/svara';
928
+ *
929
+ * const app = new SvaraApp();
930
+ *
931
+ * const agent = new SvaraAgent({
932
+ * name: 'Support Bot',
933
+ * model: 'gpt-4o-mini',
934
+ * knowledge: './docs',
935
+ * });
936
+ *
937
+ * app.route('/chat', agent.handler());
938
+ * app.listen(3000);
939
+ * ```
940
+ *
941
+ * @example With tools and channels
942
+ * ```ts
943
+ * import { SvaraAgent, createTool } from '@yesvara/svara';
944
+ *
945
+ * const agent = new SvaraAgent({ name: 'Aria', model: 'gpt-4o' });
946
+ *
947
+ * agent
948
+ * .addTool(createTool({
949
+ * name: 'get_time',
950
+ * description: 'Get current date and time',
951
+ * parameters: {},
952
+ * async run() { return { time: new Date().toISOString() }; },
953
+ * }))
954
+ * .connectChannel('telegram', { token: process.env.TG_TOKEN! })
955
+ * .connectChannel('whatsapp', {
956
+ * token: process.env.WA_TOKEN!,
957
+ * phoneId: process.env.WA_PHONE_ID!,
958
+ * verifyToken: process.env.WA_VERIFY_TOKEN!,
959
+ * });
960
+ *
961
+ * await agent.start();
962
+ * ```
963
+ */
964
+
965
+ declare const VERSION = "0.1.0";
966
+
967
+ export { type AgentConfig, type AgentContext, type AppOptions, type ChannelName, Chunker, DocumentLoader, type MemoryOptions, type ProcessResult, SvaraAgent, SvaraApp, SvaraDB, TelegramChannel, type TelegramChannelConfig, type Tool, type ToolParameter, VERSION, VectorRetriever, WebChannel, type WebChannelConfig, WhatsAppChannel, type WhatsAppChannelConfig, createTool };