@yesvara/svara 0.1.2 → 0.2.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.
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 contributionsbug reports, feature requests, documentation improvements, and pull requests.
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
@@ -3,7 +3,7 @@
3
3
 
4
4
  <!-- # @yesvara/svara -->
5
5
 
6
- **Build AI agents in 15 lines. Ship to production.**
6
+ **Build AI agents in less than 9 lines. Ship to production.**
7
7
 
8
8
  A batteries-included Node.js framework for building agentic AI backends.
9
9
  Multi-channel, RAG-ready, and designed for developers who value simplicity.
@@ -22,18 +22,16 @@ Multi-channel, RAG-ready, and designed for developers who value simplicity.
22
22
  Most AI frameworks make you think about infrastructure. SvaraJS makes you think about your agent.
23
23
 
24
24
  ```ts
25
- import { SvaraApp, SvaraAgent } from '@yesvara/svara';
26
-
27
- const app = new SvaraApp();
25
+ import { SvaraApp, SvaraAgent, createTool } from '@yesvara/svara';
28
26
 
29
27
  const agent = new SvaraAgent({
30
28
  name: 'Support Bot',
31
29
  model: 'gpt-4o-mini', // provider auto-detected
32
- knowledge: './docs', // PDF, MD, TXT just point to a folder
30
+ knowledge: './docs', // PDF, MD, TXT, just point to a folder
31
+ tools: [tool_1, tool_2, tool_3], // Agent choose the right tool for answer
33
32
  });
34
33
 
35
- app.route('/chat', agent.handler());
36
- app.listen(3000);
34
+ const app = new SvaraApp().route('/chat', agent.handler()).listen(3000);
37
35
  // Done. Your agent handles 1000 conversations.
38
36
  ```
39
37
 
@@ -44,7 +42,7 @@ That's it. No pipeline setup. No embedding boilerplate. No webhook configuration
44
42
 
45
43
  ## Features
46
44
 
47
- | | |
45
+ |||
48
46
  |---|---|
49
47
  | **Zero-config LLM** | Pass a model name, provider is auto-detected |
50
48
  | **Instant RAG** | Point to a folder, documents are indexed automatically |
@@ -359,7 +357,7 @@ agent
359
357
  verifyToken: process.env.WA_VERIFY_TOKEN,
360
358
  });
361
359
 
362
- await agent.start();
360
+ await agent.start(); // Start all channels
363
361
  ```
364
362
 
365
363
  ### Events
@@ -416,12 +414,15 @@ console.log(reply); // "It's currently 14:32 UTC..."
416
414
  const agent = new SvaraAgent({
417
415
  name: 'Support Bot',
418
416
  model: 'gpt-4o-mini',
419
- knowledge: './docs',
417
+ knowledge: './docs', // Auto-loaded on first request
420
418
  systemPrompt: 'You are a customer support agent. Answer using the documentation.',
421
419
  memory: { window: 20 },
422
420
  });
423
421
 
424
- await agent.start(); // indexes documents
422
+ const app = new SvaraApp({ cors: true });
423
+ app.route('/chat', agent.handler());
424
+ app.listen(3000);
425
+ // Knowledge indexes automatically on first request
425
426
  ```
426
427
 
427
428
  ### Multi-channel (Web + Telegram + WhatsApp)
@@ -462,21 +463,105 @@ app.listen(3000);
462
463
 
463
464
  ---
464
465
 
466
+ ## Adding Knowledge & Tools at Runtime
467
+
468
+ ### Adding knowledge (dynamic indexing)
469
+
470
+ After the agent is created, add more documents **without restarting**:
471
+
472
+ ```ts
473
+ const agent = new SvaraAgent({
474
+ name: 'Support Bot',
475
+ model: 'gpt-4o-mini',
476
+ knowledge: './docs', // Initial knowledge
477
+ });
478
+
479
+ // ── Later (no restart needed) ──────────────────────
480
+ // Add a single document
481
+ await agent.addKnowledge('./policies/new-policy-2024.pdf');
482
+
483
+ // Add multiple documents
484
+ await agent.addKnowledge(['./faq.md', './terms.txt', './pricing.pdf']);
485
+
486
+ // Agent immediately has the new knowledge
487
+ ```
488
+
489
+ **Real-world example** — admin endpoint to upload documents:
490
+
491
+ ```ts
492
+ const app = new SvaraApp({ cors: true });
493
+ app.route('/chat', agent.handler());
494
+
495
+ // Admin: dynamically add knowledge
496
+ app.post('/admin/add-knowledge', async (req, res) => {
497
+ const { path } = req.body;
498
+ try {
499
+ await agent.addKnowledge(path);
500
+ res.json({ status: 'Knowledge added', path });
501
+ } catch (err) {
502
+ res.status(400).json({ error: (err as Error).message });
503
+ }
504
+ });
505
+
506
+ app.listen(3000);
507
+ ```
508
+
509
+ ### Adding tools (dynamic function calling)
510
+
511
+ Add tools at runtime with `addTool()`:
512
+
513
+ ```ts
514
+ import { SvaraAgent, createTool } from '@yesvara/svara';
515
+
516
+ const agent = new SvaraAgent({
517
+ name: 'Assistant',
518
+ model: 'gpt-4o-mini',
519
+ tools: [initialTool], // Start with one tool
520
+ });
521
+
522
+ // ── Later ────────────────────────────────────────
523
+ // Add more tools dynamically
524
+ const newTool = createTool({
525
+ name: 'send_email',
526
+ description: 'Send an email to a user',
527
+ parameters: {
528
+ to: { type: 'string', description: 'Email address', required: true },
529
+ subject: { type: 'string', description: 'Email subject', required: true },
530
+ body: { type: 'string', description: 'Email body', required: true },
531
+ },
532
+ async run({ to, subject, body }) {
533
+ // Call your email service
534
+ return { status: 'sent', to, subject };
535
+ },
536
+ });
537
+
538
+ agent.addTool(newTool);
539
+
540
+ // Agent can now use send_email tool
541
+ ```
542
+
543
+ **Chainable tool registration** (multiple tools):
544
+
545
+ ```ts
546
+ agent
547
+ .addTool(emailTool)
548
+ .addTool(databaseTool)
549
+ .addTool(slackTool)
550
+ .addTool(webhookTool);
551
+ ```
552
+
553
+ ---
554
+
465
555
  ## CLI
466
556
 
557
+ ### Create a new project
558
+
467
559
  ```bash
468
- # Scaffold a new project
469
560
  svara new my-app
470
-
471
- # Start dev server with hot-reload
472
- svara dev
473
-
474
- # Build for production
475
- svara build
476
561
  ```
477
562
 
563
+ Output:
478
564
  ```
479
- $ svara new my-app
480
565
  ✨ Creating SvaraJS project: my-app
481
566
 
482
567
  ✓ package.json
@@ -494,6 +579,89 @@ $ svara new my-app
494
579
  npm run dev
495
580
  ```
496
581
 
582
+ Options:
583
+ - `--template <name>` — Use a specific template (default: `basic`)
584
+ - `basic` — Simple agent with HTTP endpoint
585
+ - `rag` — RAG-powered agent with document loader
586
+ - `multi-channel` — Web + Telegram + WhatsApp setup
587
+ - `tools` — Agent with tool calling examples
588
+
589
+ ### Start development server
590
+
591
+ ```bash
592
+ svara dev
593
+ ```
594
+
595
+ Features:
596
+ - Hot-reload on file changes
597
+ - Auto-restart agent on code updates
598
+ - Debug logging enabled
599
+ - Serves on `http://localhost:3000` (configurable)
600
+
601
+ Options:
602
+ - `--port <number>` — Custom port (default: `3000`)
603
+ - `--watch <glob>` — Watch additional paths (default: `src/**`)
604
+ - `--env <file>` — Load custom .env file
605
+
606
+ ### Build for production
607
+
608
+ ```bash
609
+ svara build
610
+ ```
611
+
612
+ Outputs:
613
+ - `dist/` — Compiled JavaScript
614
+ - `dist/index.js` — Entry point (ready for Node or Docker)
615
+ - Source maps and type declarations included
616
+
617
+ Options:
618
+ - `--minify` — Minify output
619
+ - `--sourcemaps` — Include source maps (default: true)
620
+ - `--outdir <path>` — Custom output directory (default: `dist/`)
621
+
622
+ ### Running built projects
623
+
624
+ ```bash
625
+ # After building
626
+ node dist/index.js
627
+
628
+ # Or with env file
629
+ NODE_ENV=production OPENAI_API_KEY=sk-... node dist/index.js
630
+ ```
631
+
632
+ ### Database management
633
+
634
+ ```bash
635
+ # Initialize database (auto-creates tables)
636
+ svara db init
637
+
638
+ # Show database schema
639
+ svara db schema
640
+
641
+ # Export users and conversation history
642
+ svara db export --format json
643
+ svara db export --format csv --table svara_messages
644
+
645
+ # Query database directly
646
+ svara db query "SELECT COUNT(*) FROM svara_users"
647
+
648
+ # Reset database (⚠️ deletes all data)
649
+ svara db reset
650
+
651
+ # Backup database
652
+ svara db backup --output backup-2026-01-15.db
653
+
654
+ # Restore from backup
655
+ svara db restore --input backup-2026-01-15.db
656
+ ```
657
+
658
+ Options:
659
+ - `--db <path>` — Custom database path (default: `./data/svara.db`)
660
+ - `--format <type>` — Export format: `json`, `csv`, `sql` (default: `json`)
661
+ - `--table <name>` — Specific table to export
662
+ - `--output <path>` — Output file path
663
+ - `--force` — Skip confirmation prompts (use with `reset` carefully!)
664
+
497
665
  ---
498
666
 
499
667
  ## Built-in Database
package/dist/cli/index.js CHANGED
@@ -97,7 +97,7 @@ function generatePackageJson(name) {
97
97
  start: "node dist/index.js"
98
98
  },
99
99
  dependencies: {
100
- svarajs: "latest",
100
+ "@yesvara/svara": "^0.1.3",
101
101
  dotenv: "^16.4.5"
102
102
  },
103
103
  devDependencies: {
@@ -144,55 +144,53 @@ function generateIndexFile(name, provider, channels) {
144
144
  anthropic: "claude-opus-4-6",
145
145
  ollama: "llama3"
146
146
  };
147
- const channelSetup = channels.map((ch) => {
148
- if (ch === "web") return `agent.use('web', { port: 3000, cors: true });`;
149
- if (ch === "telegram") return `agent.use('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! });`;
150
- if (ch === "whatsapp") return [
151
- `agent.use('whatsapp', {`,
152
- ` token: process.env.WA_ACCESS_TOKEN!,`,
153
- ` phoneId: process.env.WA_PHONE_ID!,`,
154
- ` verifyToken: process.env.WA_VERIFY_TOKEN!,`,
155
- `});`
156
- ].join("\n");
147
+ const channelSetup = channels.includes("web") ? `const app = new SvaraApp({ cors: true });
148
+ app.route('/chat', agent.handler());
149
+ app.listen(3000);` : channels.length > 0 ? `agent
150
+ ${channels.map((ch) => {
151
+ if (ch === "telegram") return `.connectChannel('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! })`;
152
+ if (ch === "whatsapp")
153
+ return `.connectChannel('whatsapp', {
154
+ token: process.env.WA_ACCESS_TOKEN!,
155
+ phoneId: process.env.WA_PHONE_ID!,
156
+ verifyToken: process.env.WA_VERIFY_TOKEN!,
157
+ })`;
157
158
  return "";
158
- }).filter(Boolean).join("\n");
159
+ }).filter(Boolean).join("\n ")};
160
+ await agent.start();` : "";
159
161
  return `import 'dotenv/config';
160
- import { svara } from 'svarajs';
162
+ import { SvaraApp, SvaraAgent, createTool } from '@yesvara/svara';
161
163
 
162
164
  /**
163
165
  * ${name} \u2014 powered by SvaraJS
164
166
  */
165
- const agent = svara({
166
- llm: {
167
- provider: '${provider}',
168
- model: '${modelMap[provider] ?? "gpt-4o"}',
169
- },
170
- systemPrompt: \`You are a helpful AI assistant called ${name}.
171
- Be concise, friendly, and always try your best to help.\`,
172
- memory: {
173
- type: 'conversation',
174
- maxMessages: 20,
175
- },
176
- verbose: true,
177
- });
178
167
 
179
- // \u2500\u2500 Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
180
- agent.tool('get_time', {
168
+ // Define tools
169
+ const timeTool = createTool({
170
+ name: 'get_time',
181
171
  description: 'Get the current date and time',
182
172
  parameters: {},
183
- execute: async () => ({
184
- datetime: new Date().toISOString(),
185
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
186
- }),
173
+ async run() {
174
+ return {
175
+ datetime: new Date().toISOString(),
176
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
177
+ };
178
+ },
179
+ });
180
+
181
+ // Create agent
182
+ const agent = new SvaraAgent({
183
+ name: '${name}',
184
+ model: '${modelMap[provider] ?? "gpt-4o"}',
185
+ systemPrompt: 'You are a helpful AI assistant. Be concise and friendly.',
186
+ tools: [timeTool],
187
+ knowledge: './docs', // Add your documents here for RAG
187
188
  });
188
189
 
189
- // \u2500\u2500 Channels \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
190
+ // Setup channels
190
191
  ${channelSetup}
191
192
 
192
- // \u2500\u2500 Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
193
- agent.start().then(() => {
194
- console.log('\u{1F680} ${name} is running!');
195
- });
193
+ console.log('\u2728 ${name} is running!');
196
194
  `;
197
195
  }
198
196
  function generateGitignore() {
@@ -9,7 +9,7 @@ var pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
9
9
  var program = new Command();
10
10
  program.name("svara").description(pkg.description).version(pkg.version, "-v, --version");
11
11
  program.command("new <name>").description("Create a new SvaraJS project").option("--provider <provider>", "LLM provider (openai|anthropic|ollama)", "openai").option("--channel <channels...>", "Channels to include", ["web"]).option("--no-install", "Skip npm install").action(async (name, opts) => {
12
- const { newProject } = await import("../new-7K4NIDZO.mjs");
12
+ const { newProject } = await import("../new-ULRP6IUQ.mjs");
13
13
  await newProject({
14
14
  name,
15
15
  provider: opts.provider,
package/dist/index.d.mts CHANGED
@@ -446,6 +446,7 @@ declare class SvaraAgent extends EventEmitter {
446
446
  private retriever;
447
447
  private knowledgePaths;
448
448
  private isStarted;
449
+ private isKnowledgeInitialized;
449
450
  private db;
450
451
  constructor(config: AgentConfig);
451
452
  /**
package/dist/index.d.ts CHANGED
@@ -446,6 +446,7 @@ declare class SvaraAgent extends EventEmitter {
446
446
  private retriever;
447
447
  private knowledgePaths;
448
448
  private isStarted;
449
+ private isKnowledgeInitialized;
449
450
  private db;
450
451
  constructor(config: AgentConfig);
451
452
  /**
package/dist/index.js CHANGED
@@ -1701,6 +1701,7 @@ var SvaraAgent = class extends import_events.default {
1701
1701
  // Store VectorRetriever for retrieveChunks access
1702
1702
  knowledgePaths = [];
1703
1703
  isStarted = false;
1704
+ isKnowledgeInitialized = false;
1704
1705
  db;
1705
1706
  constructor(config) {
1706
1707
  super();
@@ -1809,6 +1810,15 @@ var SvaraAgent = class extends import_events.default {
1809
1810
  */
1810
1811
  handler() {
1811
1812
  return async (req, res) => {
1813
+ if (this.knowledgePaths.length > 0 && !this.isKnowledgeInitialized) {
1814
+ try {
1815
+ await this.initKnowledge(this.knowledgePaths);
1816
+ this.isKnowledgeInitialized = true;
1817
+ } catch (err) {
1818
+ const error = err;
1819
+ this.log("error", `Failed to initialize knowledge: ${error.message}`);
1820
+ }
1821
+ }
1812
1822
  const { message, sessionId, userId } = req.body;
1813
1823
  if (!message?.trim()) {
1814
1824
  res.status(400).json({
package/dist/index.mjs CHANGED
@@ -891,6 +891,7 @@ var SvaraAgent = class extends EventEmitter {
891
891
  // Store VectorRetriever for retrieveChunks access
892
892
  knowledgePaths = [];
893
893
  isStarted = false;
894
+ isKnowledgeInitialized = false;
894
895
  db;
895
896
  constructor(config) {
896
897
  super();
@@ -999,6 +1000,15 @@ var SvaraAgent = class extends EventEmitter {
999
1000
  */
1000
1001
  handler() {
1001
1002
  return async (req, res) => {
1003
+ if (this.knowledgePaths.length > 0 && !this.isKnowledgeInitialized) {
1004
+ try {
1005
+ await this.initKnowledge(this.knowledgePaths);
1006
+ this.isKnowledgeInitialized = true;
1007
+ } catch (err) {
1008
+ const error = err;
1009
+ this.log("error", `Failed to initialize knowledge: ${error.message}`);
1010
+ }
1011
+ }
1002
1012
  const { message, sessionId, userId } = req.body;
1003
1013
  if (!message?.trim()) {
1004
1014
  res.status(400).json({
@@ -66,7 +66,7 @@ function generatePackageJson(name) {
66
66
  start: "node dist/index.js"
67
67
  },
68
68
  dependencies: {
69
- svarajs: "latest",
69
+ "@yesvara/svara": "^0.1.3",
70
70
  dotenv: "^16.4.5"
71
71
  },
72
72
  devDependencies: {
@@ -113,55 +113,53 @@ function generateIndexFile(name, provider, channels) {
113
113
  anthropic: "claude-opus-4-6",
114
114
  ollama: "llama3"
115
115
  };
116
- const channelSetup = channels.map((ch) => {
117
- if (ch === "web") return `agent.use('web', { port: 3000, cors: true });`;
118
- if (ch === "telegram") return `agent.use('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! });`;
119
- if (ch === "whatsapp") return [
120
- `agent.use('whatsapp', {`,
121
- ` token: process.env.WA_ACCESS_TOKEN!,`,
122
- ` phoneId: process.env.WA_PHONE_ID!,`,
123
- ` verifyToken: process.env.WA_VERIFY_TOKEN!,`,
124
- `});`
125
- ].join("\n");
116
+ const channelSetup = channels.includes("web") ? `const app = new SvaraApp({ cors: true });
117
+ app.route('/chat', agent.handler());
118
+ app.listen(3000);` : channels.length > 0 ? `agent
119
+ ${channels.map((ch) => {
120
+ if (ch === "telegram") return `.connectChannel('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! })`;
121
+ if (ch === "whatsapp")
122
+ return `.connectChannel('whatsapp', {
123
+ token: process.env.WA_ACCESS_TOKEN!,
124
+ phoneId: process.env.WA_PHONE_ID!,
125
+ verifyToken: process.env.WA_VERIFY_TOKEN!,
126
+ })`;
126
127
  return "";
127
- }).filter(Boolean).join("\n");
128
+ }).filter(Boolean).join("\n ")};
129
+ await agent.start();` : "";
128
130
  return `import 'dotenv/config';
129
- import { svara } from 'svarajs';
131
+ import { SvaraApp, SvaraAgent, createTool } from '@yesvara/svara';
130
132
 
131
133
  /**
132
134
  * ${name} \u2014 powered by SvaraJS
133
135
  */
134
- const agent = svara({
135
- llm: {
136
- provider: '${provider}',
137
- model: '${modelMap[provider] ?? "gpt-4o"}',
138
- },
139
- systemPrompt: \`You are a helpful AI assistant called ${name}.
140
- Be concise, friendly, and always try your best to help.\`,
141
- memory: {
142
- type: 'conversation',
143
- maxMessages: 20,
144
- },
145
- verbose: true,
146
- });
147
136
 
148
- // \u2500\u2500 Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
149
- agent.tool('get_time', {
137
+ // Define tools
138
+ const timeTool = createTool({
139
+ name: 'get_time',
150
140
  description: 'Get the current date and time',
151
141
  parameters: {},
152
- execute: async () => ({
153
- datetime: new Date().toISOString(),
154
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
155
- }),
142
+ async run() {
143
+ return {
144
+ datetime: new Date().toISOString(),
145
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
146
+ };
147
+ },
156
148
  });
157
149
 
158
- // \u2500\u2500 Channels \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
150
+ // Create agent
151
+ const agent = new SvaraAgent({
152
+ name: '${name}',
153
+ model: '${modelMap[provider] ?? "gpt-4o"}',
154
+ systemPrompt: 'You are a helpful AI assistant. Be concise and friendly.',
155
+ tools: [timeTool],
156
+ knowledge: './docs', // Add your documents here for RAG
157
+ });
158
+
159
+ // Setup channels
159
160
  ${channelSetup}
160
161
 
161
- // \u2500\u2500 Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
162
- agent.start().then(() => {
163
- console.log('\u{1F680} ${name} is running!');
164
- });
162
+ console.log('\u2728 ${name} is running!');
165
163
  `;
166
164
  }
167
165
  function generateGitignore() {
@@ -31,11 +31,9 @@ Always be friendly and professional.`,
31
31
  memory: { window: 20 },
32
32
  });
33
33
 
34
- // You can also add knowledge dynamically (hot reload, no restart needed)
35
- // await agent.addKnowledge('./new-policy-2024.pdf');
36
-
37
34
  const app = new SvaraApp({ cors: true });
38
35
  app.route('/chat', agent.handler());
39
36
 
40
- await agent.start(); // indexes documents
41
37
  app.listen(3000);
38
+ console.log('✓ Agent running on http://localhost:3000');
39
+ console.log(' Knowledge base auto-loads on first request');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yesvara/svara",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Build AI agents in 15 lines of code. Multi-channel, RAG-ready, production-grade.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -86,7 +86,7 @@ function generatePackageJson(name: string): string {
86
86
  start: 'node dist/index.js',
87
87
  },
88
88
  dependencies: {
89
- svarajs: 'latest',
89
+ '@yesvara/svara': '^0.1.3',
90
90
  dotenv: '^16.4.5',
91
91
  },
92
92
  devDependencies: {
@@ -147,59 +147,53 @@ function generateIndexFile(
147
147
  ollama: 'llama3',
148
148
  };
149
149
 
150
- const channelSetup = channels
151
- .map((ch) => {
152
- if (ch === 'web') return `agent.use('web', { port: 3000, cors: true });`;
153
- if (ch === 'telegram') return `agent.use('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! });`;
154
- if (ch === 'whatsapp') return [
155
- `agent.use('whatsapp', {`,
156
- ` token: process.env.WA_ACCESS_TOKEN!,`,
157
- ` phoneId: process.env.WA_PHONE_ID!,`,
158
- ` verifyToken: process.env.WA_VERIFY_TOKEN!,`,
159
- `});`,
160
- ].join('\n');
161
- return '';
162
- })
163
- .filter(Boolean)
164
- .join('\n');
150
+ const channelSetup = channels.includes('web')
151
+ ? `const app = new SvaraApp({ cors: true });\napp.route('/chat', agent.handler());\napp.listen(3000);`
152
+ : channels.length > 0
153
+ ? `agent\n ${channels
154
+ .map((ch) => {
155
+ if (ch === 'telegram') return `.connectChannel('telegram', { token: process.env.TELEGRAM_BOT_TOKEN! })`;
156
+ if (ch === 'whatsapp')
157
+ return `.connectChannel('whatsapp', {\n token: process.env.WA_ACCESS_TOKEN!,\n phoneId: process.env.WA_PHONE_ID!,\n verifyToken: process.env.WA_VERIFY_TOKEN!,\n })`;
158
+ return '';
159
+ })
160
+ .filter(Boolean)
161
+ .join('\n ')};\nawait agent.start();`
162
+ : '';
165
163
 
166
164
  return `import 'dotenv/config';
167
- import { svara } from 'svarajs';
165
+ import { SvaraApp, SvaraAgent, createTool } from '@yesvara/svara';
168
166
 
169
167
  /**
170
168
  * ${name} — powered by SvaraJS
171
169
  */
172
- const agent = svara({
173
- llm: {
174
- provider: '${provider}',
175
- model: '${modelMap[provider] ?? 'gpt-4o'}',
176
- },
177
- systemPrompt: \`You are a helpful AI assistant called ${name}.
178
- Be concise, friendly, and always try your best to help.\`,
179
- memory: {
180
- type: 'conversation',
181
- maxMessages: 20,
182
- },
183
- verbose: true,
184
- });
185
170
 
186
- // ── Tools ──────────────────────────────────────────────────────────────────
187
- agent.tool('get_time', {
171
+ // Define tools
172
+ const timeTool = createTool({
173
+ name: 'get_time',
188
174
  description: 'Get the current date and time',
189
175
  parameters: {},
190
- execute: async () => ({
191
- datetime: new Date().toISOString(),
192
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
193
- }),
176
+ async run() {
177
+ return {
178
+ datetime: new Date().toISOString(),
179
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
180
+ };
181
+ },
194
182
  });
195
183
 
196
- // ── Channels ────────────────────────────────────────────────────────────────
184
+ // Create agent
185
+ const agent = new SvaraAgent({
186
+ name: '${name}',
187
+ model: '${modelMap[provider] ?? 'gpt-4o'}',
188
+ systemPrompt: 'You are a helpful AI assistant. Be concise and friendly.',
189
+ tools: [timeTool],
190
+ knowledge: './docs', // Add your documents here for RAG
191
+ });
192
+
193
+ // Setup channels
197
194
  ${channelSetup}
198
195
 
199
- // ── Start ────────────────────────────────────────────────────────────────────
200
- agent.start().then(() => {
201
- console.log('🚀 ${name} is running!');
202
- });
196
+ console.log('✨ ${name} is running!');
203
197
  `;
204
198
  }
205
199
 
package/src/core/agent.ts CHANGED
@@ -173,6 +173,7 @@ export class SvaraAgent extends EventEmitter {
173
173
  private retriever: any = null; // Store VectorRetriever for retrieveChunks access
174
174
  private knowledgePaths: string[] = [];
175
175
  private isStarted = false;
176
+ private isKnowledgeInitialized = false;
176
177
  private db: SvaraDB;
177
178
 
178
179
  constructor(config: AgentConfig) {
@@ -303,6 +304,17 @@ export class SvaraAgent extends EventEmitter {
303
304
  */
304
305
  handler(): RequestHandler {
305
306
  return async (req, res) => {
307
+ // Auto-initialize knowledge on first request (lazy loading)
308
+ if (this.knowledgePaths.length > 0 && !this.isKnowledgeInitialized) {
309
+ try {
310
+ await this.initKnowledge(this.knowledgePaths);
311
+ this.isKnowledgeInitialized = true;
312
+ } catch (err) {
313
+ const error = err as Error;
314
+ this.log('error', `Failed to initialize knowledge: ${error.message}`);
315
+ }
316
+ }
317
+
306
318
  const { message, sessionId, userId } = req.body as {
307
319
  message?: string;
308
320
  sessionId?: string;
package/svara@1.0.0 DELETED
File without changes
package/test-rag.ts DELETED
@@ -1,20 +0,0 @@
1
- import 'dotenv/config';
2
- import { SvaraApp, SvaraAgent } from './src/index.js';
3
-
4
- async function main() {
5
- const app = new SvaraApp({ cors: true });
6
-
7
- const agent = new SvaraAgent({
8
- name: 'TestAgent',
9
- model: 'gpt-4o-mini',
10
- knowledge: '/Users/920078/Documents/svara/contoh_folder_knowledge/**/*',
11
- verbose: true,
12
- });
13
-
14
- await agent.start();
15
- app.route('/chat', agent.handler());
16
- app.listen(3000);
17
- console.log('✓ Test server on port 3000');
18
- }
19
-
20
- main().catch(console.error);
package/tsx DELETED
File without changes