hybard-agent 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.
@@ -0,0 +1,585 @@
1
+ /**
2
+ * Hybard Coding Model — LLM-powered code generation with context understanding.
3
+ *
4
+ * Architecture:
5
+ * User Request → Tokenization → Context Building → LLM → Code Generation
6
+ *
7
+ * Features:
8
+ * - Multi-language support (Python, JS, TS, Dart, SQL, etc.)
9
+ * - Framework-aware code generation
10
+ * - Project context understanding
11
+ * - Error-aware code fixing
12
+ * - Bengali/English natural language to code
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const { HybardAI } = require('./online');
18
+ const { ProjectDetector, CodebaseSearch } = require('./hybard-agent');
19
+
20
+ // ─── Language Configurations ────────────────────────────
21
+
22
+ const LANGUAGE_CONFIG = {
23
+ python: {
24
+ extensions: ['.py'],
25
+ frameworks: ['Django', 'Flask', 'FastAPI', 'PyTorch', 'TensorFlow'],
26
+ entryPoints: ['main.py', 'app.py', 'manage.py'],
27
+ fileTemplates: {
28
+ main: (name) => `def main():
29
+ print("Hello from ${name}")
30
+
31
+ if __name__ == "__main__":
32
+ main()
33
+ `,
34
+ test: (name) => `import pytest
35
+
36
+ def test_main():
37
+ assert True
38
+ `,
39
+ },
40
+ },
41
+ javascript: {
42
+ extensions: ['.js', '.jsx'],
43
+ frameworks: ['React', 'Next.js', 'Express', 'Vue', 'Angular'],
44
+ entryPoints: ['index.js', 'src/index.js', 'src/main.js'],
45
+ fileTemplates: {
46
+ main: (name) => `console.log("Hello from ${name}");
47
+ `,
48
+ test: (name) => `describe('${name}', () => {
49
+ it('should work', () => {
50
+ expect(true).toBe(true);
51
+ });
52
+ });
53
+ `,
54
+ },
55
+ },
56
+ typescript: {
57
+ extensions: ['.ts', '.tsx'],
58
+ frameworks: ['React', 'Next.js', 'NestJS', 'Express'],
59
+ entryPoints: ['index.ts', 'src/index.ts', 'src/main.ts'],
60
+ fileTemplates: {
61
+ main: (name) => `console.log("Hello from ${name}");
62
+ `,
63
+ test: (name) => `import { describe, it, expect } from 'vitest';
64
+
65
+ describe('${name}', () => {
66
+ it('should work', () => {
67
+ expect(true).toBe(true);
68
+ });
69
+ });
70
+ `,
71
+ },
72
+ },
73
+ dart: {
74
+ extensions: ['.dart'],
75
+ frameworks: ['Flutter'],
76
+ entryPoints: ['lib/main.dart'],
77
+ fileTemplates: {
78
+ main: (name) => `import 'package:flutter/material.dart';
79
+
80
+ void main() {
81
+ runApp(const MyApp());
82
+ }
83
+
84
+ class MyApp extends StatelessWidget {
85
+ const MyApp({super.key});
86
+
87
+ @override
88
+ Widget build(BuildContext context) {
89
+ return MaterialApp(
90
+ title: '${name}',
91
+ theme: ThemeData(primarySwatch: Colors.blue),
92
+ home: const HomeScreen(),
93
+ );
94
+ }
95
+ }
96
+
97
+ class HomeScreen extends StatelessWidget {
98
+ const HomeScreen({super.key});
99
+
100
+ @override
101
+ Widget build(BuildContext context) {
102
+ return Scaffold(
103
+ appBar: AppBar(title: const Text('${name}')),
104
+ body: const Center(
105
+ child: Text('Hello from ${name}'),
106
+ ),
107
+ );
108
+ }
109
+ }
110
+ `,
111
+ },
112
+ },
113
+ sql: {
114
+ extensions: ['.sql'],
115
+ frameworks: ['PostgreSQL', 'MySQL', 'SQLite'],
116
+ entryPoints: ['schema.sql', 'migrations/'],
117
+ fileTemplates: {
118
+ main: (name) => `-- ${name} Database Schema
119
+ CREATE TABLE users (
120
+ id SERIAL PRIMARY KEY,
121
+ username VARCHAR(50) UNIQUE NOT NULL,
122
+ email VARCHAR(100) UNIQUE NOT NULL,
123
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
124
+ );
125
+ `,
126
+ },
127
+ },
128
+ html: {
129
+ extensions: ['.html'],
130
+ frameworks: ['Tailwind CSS', 'Bootstrap'],
131
+ entryPoints: ['index.html'],
132
+ fileTemplates: {
133
+ main: (name) => `<!DOCTYPE html>
134
+ <html lang="en">
135
+ <head>
136
+ <meta charset="UTF-8">
137
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
138
+ <title>${name}</title>
139
+ </head>
140
+ <body>
141
+ <h1>Hello from ${name}</h1>
142
+ </body>
143
+ </html>
144
+ `,
145
+ },
146
+ },
147
+ css: {
148
+ extensions: ['.css'],
149
+ frameworks: ['Tailwind CSS', 'Bootstrap'],
150
+ entryPoints: ['style.css'],
151
+ fileTemplates: {
152
+ main: (name) => `/* ${name} Styles */
153
+ * {
154
+ margin: 0;
155
+ padding: 0;
156
+ box-sizing: border-box;
157
+ }
158
+
159
+ body {
160
+ font-family: system-ui, -apple-system, sans-serif;
161
+ }
162
+ `,
163
+ },
164
+ },
165
+ };
166
+
167
+ // ─── Context Builder ────────────────────────────────────
168
+
169
+ class ContextBuilder {
170
+ constructor(rootDir = process.cwd()) {
171
+ this.rootDir = rootDir;
172
+ this.detector = new ProjectDetector(rootDir);
173
+ this.searcher = new CodebaseSearch(rootDir);
174
+ this.projectInfo = null;
175
+ }
176
+
177
+ buildContext(userRequest) {
178
+ this.projectInfo = this.detector.detect();
179
+
180
+ let context = '';
181
+
182
+ // 1. Project Context
183
+ context += this.buildProjectContext();
184
+
185
+ // 2. Relevant Files (based on user request)
186
+ context += this.buildRelevantFilesContext(userRequest);
187
+
188
+ // 3. Framework Context
189
+ context += this.buildFrameworkContext();
190
+
191
+ // 4. Dependencies Context
192
+ context += this.buildDependenciesContext();
193
+
194
+ // 5. Documentation Context
195
+ context += this.buildDocumentationContext(userRequest);
196
+
197
+ return context;
198
+ }
199
+
200
+ buildProjectContext() {
201
+ if (!this.projectInfo) return '';
202
+
203
+ let ctx = '\n=== PROJECT CONTEXT ===\n';
204
+ ctx += `Type: ${this.projectInfo.type}\n`;
205
+ ctx += `Languages: ${this.projectInfo.languages.join(', ')}\n`;
206
+ ctx += `Frameworks: ${this.projectInfo.frameworks.join(', ')}\n`;
207
+ ctx += `Entry Points: ${this.projectInfo.entryPoints.join(', ')}\n`;
208
+ ctx += `Config Files: ${this.projectInfo.configFiles.join(', ')}\n`;
209
+ return ctx;
210
+ }
211
+
212
+ buildRelevantFilesContext(userRequest) {
213
+ const searchTerms = this.extractSearchTerms(userRequest);
214
+ if (searchTerms.length === 0) return '';
215
+
216
+ let ctx = '\n=== RELEVANT FILES ===\n';
217
+ for (const term of searchTerms.slice(0, 3)) {
218
+ const results = this.searcher.searchCode(term);
219
+ if (results.length > 0) {
220
+ ctx += `\nSearch "${term}":\n`;
221
+ for (const result of results.slice(0, 3)) {
222
+ ctx += ` ${result.file}:\n`;
223
+ for (const match of result.matches.slice(0, 2)) {
224
+ ctx += ` Line ${match.line}: ${match.content}\n`;
225
+ }
226
+ }
227
+ }
228
+ }
229
+ return ctx;
230
+ }
231
+
232
+ buildFrameworkContext() {
233
+ if (!this.projectInfo || this.projectInfo.frameworks.length === 0) return '';
234
+
235
+ let ctx = '\n=== FRAMEWORK CONTEXT ===\n';
236
+ for (const framework of this.projectInfo.frameworks) {
237
+ ctx += `Framework: ${framework}\n`;
238
+ ctx += ` - Use ${framework} patterns and conventions\n`;
239
+ ctx += ` - Follow ${framework} best practices\n`;
240
+ }
241
+ return ctx;
242
+ }
243
+
244
+ buildDependenciesContext() {
245
+ if (!this.projectInfo) return '';
246
+
247
+ let ctx = '\n=== DEPENDENCIES ===\n';
248
+ const deps = this.projectInfo.dependencies;
249
+
250
+ if (deps.npm) {
251
+ ctx += 'npm packages:\n';
252
+ ctx += ` ${deps.npm.dependencies.slice(0, 10).join(', ')}\n`;
253
+ }
254
+
255
+ if (deps.pip) {
256
+ ctx += 'pip packages:\n';
257
+ ctx += ` ${deps.pip.slice(0, 10).join(', ')}\n`;
258
+ }
259
+
260
+ return ctx;
261
+ }
262
+
263
+ buildDocumentationContext(userRequest) {
264
+ const lower = userRequest.toLowerCase();
265
+ let ctx = '\n=== DOCUMENTATION CONTEXT ===\n';
266
+
267
+ // Add relevant documentation hints
268
+ if (lower.includes('flutter') || lower.includes('dart')) {
269
+ ctx += 'Flutter: Use Material Design, StatefulWidget for state, StatelessWidget for static UI.\n';
270
+ }
271
+ if (lower.includes('react') || lower.includes('next')) {
272
+ ctx += 'React: Use functional components with hooks, JSX syntax.\n';
273
+ }
274
+ if (lower.includes('fastapi') || lower.includes('python api')) {
275
+ ctx += 'FastAPI: Use async def, Pydantic models, dependency injection.\n';
276
+ }
277
+ if (lower.includes('express') || lower.includes('node')) {
278
+ ctx += 'Express: Use middleware pattern, req/res objects, router modules.\n';
279
+ }
280
+
281
+ return ctx;
282
+ }
283
+
284
+ extractSearchTerms(userRequest) {
285
+ const terms = [];
286
+ const words = userRequest.toLowerCase().split(/\s+/);
287
+
288
+ // Extract meaningful terms
289
+ const meaningfulWords = words.filter(w => w.length > 3 && !['this', 'that', 'with', 'from', 'have', 'will', 'should', 'would', 'could'].includes(w));
290
+ terms.push(...meaningfulWords.slice(0, 5));
291
+
292
+ return terms;
293
+ }
294
+ }
295
+
296
+ // ─── Code Generator ─────────────────────────────────────
297
+
298
+ class CodeGenerator {
299
+ constructor(ai) {
300
+ this.ai = ai;
301
+ }
302
+
303
+ async generate(userRequest, context = '', language = null) {
304
+ const detectedLanguage = language || this.detectLanguage(userRequest);
305
+ const langConfig = LANGUAGE_CONFIG[detectedLanguage] || LANGUAGE_CONFIG.javascript;
306
+
307
+ const systemPrompt = this.buildSystemPrompt(detectedLanguage, langConfig);
308
+ const fullPrompt = this.buildFullPrompt(userRequest, context, detectedLanguage);
309
+
310
+ const response = await this.ai.chat(fullPrompt, { system: systemPrompt });
311
+
312
+ return {
313
+ response,
314
+ language: detectedLanguage,
315
+ codeBlocks: this.extractCodeBlocks(response),
316
+ };
317
+ }
318
+
319
+ buildSystemPrompt(language, langConfig) {
320
+ return `You are Hybard AI Coding Model — an expert ${language} programmer.
321
+
322
+ LANGUAGE: ${language}
323
+ FRAMEWORKS: ${langConfig.frameworks.join(', ')}
324
+
325
+ RULES:
326
+ 1. Generate clean, working, production-ready code
327
+ 2. Follow ${language} best practices and conventions
328
+ 3. Use proper error handling
329
+ 4. Add comments only when necessary
330
+ 5. Use meaningful variable and function names
331
+ 6. Include type annotations where applicable
332
+ 7. Follow the existing project structure and patterns
333
+
334
+ CODE FORMAT:
335
+ - Return code in markdown code blocks with language tag
336
+ - Use \`\`\`${language} for code blocks
337
+ - Include file paths when creating multiple files
338
+
339
+ EXAMPLE:
340
+ \`\`\`${language}
341
+ // code here
342
+ \`\`\`
343
+ `;
344
+ }
345
+
346
+ buildFullPrompt(userRequest, context, language) {
347
+ let prompt = '';
348
+
349
+ if (context) {
350
+ prompt += context + '\n\n';
351
+ }
352
+
353
+ prompt += `USER REQUEST: ${userRequest}\n\n`;
354
+ prompt += `Generate complete, working ${language} code for this request. `;
355
+ prompt += `Follow the project context and framework patterns shown above.`;
356
+
357
+ return prompt;
358
+ }
359
+
360
+ detectLanguage(userRequest) {
361
+ const lower = userRequest.toLowerCase();
362
+
363
+ if (lower.includes('python') || lower.includes('django') || lower.includes('flask') || lower.includes('fastapi')) return 'python';
364
+ if (lower.includes('typescript') || lower.includes('ts')) return 'typescript';
365
+ if (lower.includes('react') || lower.includes('next.js') || lower.includes('nextjs')) return 'javascript';
366
+ if (lower.includes('flutter') || lower.includes('dart')) return 'dart';
367
+ if (lower.includes('sql') || lower.includes('database') || lower.includes('query')) return 'sql';
368
+ if (lower.includes('html') || lower.includes('web page') || lower.includes('landing')) return 'html';
369
+ if (lower.includes('css') || lower.includes('style')) return 'css';
370
+
371
+ return 'javascript'; // default
372
+ }
373
+
374
+ extractCodeBlocks(response) {
375
+ const blocks = [];
376
+ const regex = /```(\w*)\n([\s\S]*?)```/g;
377
+ let match;
378
+
379
+ while ((match = regex.exec(response)) !== null) {
380
+ const lang = match[1] || 'text';
381
+ const code = match[2].trim();
382
+
383
+ // Try to extract filename from code comments or headers
384
+ const filename = this.extractFilename(code, lang);
385
+
386
+ blocks.push({
387
+ language: lang,
388
+ code,
389
+ filename,
390
+ });
391
+ }
392
+
393
+ return blocks;
394
+ }
395
+
396
+ extractFilename(code, language) {
397
+ // Look for filename in comments
398
+ const filenamePatterns = [
399
+ /(?:file|filename|path):\s*(.+\.\w+)/i,
400
+ /\/\/\s*(.+\.\w+)/,
401
+ /#\s*(.+\.\w+)/,
402
+ /\/\/\s* Filename:\s*(.+)/i,
403
+ ];
404
+
405
+ for (const pattern of filenamePatterns) {
406
+ const match = code.match(pattern);
407
+ if (match) return match[1].trim();
408
+ }
409
+
410
+ // Generate default filename
411
+ const ext = LANGUAGE_CONFIG[language]?.extensions[0] || '.txt';
412
+ return `generated${ext}`;
413
+ }
414
+ }
415
+
416
+ // ─── Code Fixer ─────────────────────────────────────────
417
+
418
+ class CodeFixer {
419
+ constructor(ai) {
420
+ this.ai = ai;
421
+ }
422
+
423
+ async fix(code, error = '', language = null) {
424
+ const detectedLanguage = language || this.detectLanguage(code);
425
+
426
+ const systemPrompt = `You are a debugging expert for ${detectedLanguage}.
427
+ Fix the given code and return ONLY the corrected code in a markdown code block.
428
+ Do not include explanations unless specifically asked.`;
429
+
430
+ const prompt = error
431
+ ? `Fix this ${detectedLanguage} code. Error:\n${error}\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``
432
+ : `Fix any issues in this ${detectedLanguage} code:\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``;
433
+
434
+ const response = await this.ai.chat(prompt, { system: systemPrompt });
435
+
436
+ return {
437
+ response,
438
+ language: detectedLanguage,
439
+ codeBlocks: this.extractCodeBlocks(response),
440
+ };
441
+ }
442
+
443
+ detectLanguage(code) {
444
+ if (code.includes('def ') || code.includes('import ')) return 'python';
445
+ if (code.includes('function ') || code.includes('const ') || code.includes('=>')) return 'javascript';
446
+ if (code.includes('interface ') || code.includes(': string')) return 'typescript';
447
+ if (code.includes('Widget') || code.includes('StatelessWidget')) return 'dart';
448
+ if (code.includes('SELECT ') || code.includes('CREATE TABLE')) return 'sql';
449
+ return 'javascript';
450
+ }
451
+
452
+ extractCodeBlocks(response) {
453
+ const blocks = [];
454
+ const regex = /```(\w*)\n([\s\S]*?)```/g;
455
+ let match;
456
+
457
+ while ((match = regex.exec(response)) !== null) {
458
+ blocks.push({
459
+ language: match[1] || 'text',
460
+ code: match[2].trim(),
461
+ });
462
+ }
463
+
464
+ return blocks;
465
+ }
466
+ }
467
+
468
+ // ─── Main Coding Model ──────────────────────────────────
469
+
470
+ class CodingModel {
471
+ constructor(options = {}) {
472
+ this.ai = new HybardAI(options);
473
+ this.contextBuilder = new ContextBuilder(options.rootDir || process.cwd());
474
+ this.generator = new CodeGenerator(this.ai);
475
+ this.fixer = new CodeFixer(this.ai);
476
+ }
477
+
478
+ async generateCode(userRequest, options = {}) {
479
+ console.log(`[CodingModel] Generating code for: "${userRequest}"`);
480
+
481
+ // 1. Build context
482
+ console.log('[CodingModel] Building context...');
483
+ const context = this.contextBuilder.buildContext(userRequest);
484
+
485
+ // 2. Generate code
486
+ console.log('[CodingModel] Generating code...');
487
+ const result = await this.generator.generate(userRequest, context, options.language);
488
+
489
+ // 3. Extract and organize code blocks
490
+ const codeBlocks = result.codeBlocks;
491
+
492
+ console.log(`[CodingModel] Generated ${codeBlocks.length} code block(s)`);
493
+
494
+ return {
495
+ ...result,
496
+ context,
497
+ codeBlocks,
498
+ };
499
+ }
500
+
501
+ async fixCode(code, error = '', options = {}) {
502
+ console.log(`[CodingModel] Fixing code...`);
503
+
504
+ const result = await this.fixer.fix(code, error, options.language);
505
+
506
+ console.log(`[CodingModel] Fixed ${result.codeBlocks.length} code block(s)`);
507
+
508
+ return result;
509
+ }
510
+
511
+ async explainCode(code, language = null) {
512
+ const detectedLanguage = language || this.fixer.detectLanguage(code);
513
+
514
+ const systemPrompt = `You are a code analysis expert for ${detectedLanguage}.
515
+ Explain the given code clearly and concisely.
516
+ Cover: what it does, how it works, key patterns, and potential issues.`;
517
+
518
+ const prompt = `Explain this ${detectedLanguage} code:\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``;
519
+
520
+ return this.ai.chat(prompt, { system: systemPrompt });
521
+ }
522
+
523
+ async generateProject(goal, options = {}) {
524
+ console.log(`[CodingModel] Generating project: "${goal}"`);
525
+
526
+ const systemPrompt = `You are a project scaffolding expert.
527
+ Create a complete project structure for the given goal.
528
+ Return each file in this format:
529
+
530
+ ## filename.ext
531
+ \`\`\`language
532
+ file content here
533
+ \`\`\`
534
+
535
+ Include all necessary files:
536
+ - Main code files
537
+ - Configuration files
538
+ - Package manifests
539
+ - README
540
+ - Tests (if applicable)`;
541
+
542
+ const context = this.contextBuilder.buildContext(goal);
543
+ const prompt = context + '\n\nCreate a project scaffold for: ' + goal;
544
+
545
+ const response = await this.ai.chat(prompt, { system: systemPrompt });
546
+ const codeBlocks = this.generator.extractCodeBlocks(response);
547
+
548
+ console.log(`[CodingModel] Generated ${codeBlocks.length} files`);
549
+
550
+ return {
551
+ response,
552
+ codeBlocks,
553
+ };
554
+ }
555
+
556
+ async writeCodeToFiles(codeBlocks, targetDir = null) {
557
+ const dir = targetDir || process.cwd();
558
+ const written = [];
559
+
560
+ for (const block of codeBlocks) {
561
+ const filePath = path.join(dir, block.filename);
562
+ const fileDir = path.dirname(filePath);
563
+
564
+ if (!fs.existsSync(fileDir)) {
565
+ fs.mkdirSync(fileDir, { recursive: true });
566
+ }
567
+
568
+ fs.writeFileSync(filePath, block.code, 'utf8');
569
+ written.push(filePath);
570
+ console.log(`[CodingModel] Written: ${filePath}`);
571
+ }
572
+
573
+ return written;
574
+ }
575
+
576
+ getProjectInfo() {
577
+ return this.contextBuilder.detector.detect();
578
+ }
579
+
580
+ searchCode(query) {
581
+ return this.contextBuilder.searcher.searchCode(query);
582
+ }
583
+ }
584
+
585
+ module.exports = { CodingModel, ContextBuilder, CodeGenerator, CodeFixer, LANGUAGE_CONFIG };