outlet-orm 7.0.0 → 9.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +130 -2
  2. package/docs/skills/outlet-orm/AI.md +452 -102
  3. package/docs/skills/outlet-orm/API.md +108 -0
  4. package/docs/skills/outlet-orm/QUERIES.md +64 -0
  5. package/docs/skills/outlet-orm/SEEDS.md +47 -0
  6. package/docs/skills/outlet-orm/SKILL.md +15 -7
  7. package/package.json +1 -1
  8. package/src/AI/AIPromptEnhancer.js +170 -0
  9. package/src/AI/AIQueryBuilder.js +234 -0
  10. package/src/AI/AIQueryOptimizer.js +185 -0
  11. package/src/AI/AISeeder.js +181 -0
  12. package/src/AI/AiBridgeManager.js +287 -0
  13. package/src/AI/Builders/TextBuilder.js +170 -0
  14. package/src/AI/Contracts/AudioProviderContract.js +29 -0
  15. package/src/AI/Contracts/ChatProviderContract.js +38 -0
  16. package/src/AI/Contracts/EmbeddingsProviderContract.js +19 -0
  17. package/src/AI/Contracts/ImageProviderContract.js +19 -0
  18. package/src/AI/Contracts/ModelsProviderContract.js +26 -0
  19. package/src/AI/Contracts/ToolContract.js +25 -0
  20. package/src/AI/Facades/AiBridge.js +79 -0
  21. package/src/AI/MCPServer.js +113 -0
  22. package/src/AI/Providers/ClaudeProvider.js +64 -0
  23. package/src/AI/Providers/CustomOpenAIProvider.js +238 -0
  24. package/src/AI/Providers/GeminiProvider.js +68 -0
  25. package/src/AI/Providers/GrokProvider.js +46 -0
  26. package/src/AI/Providers/MistralProvider.js +21 -0
  27. package/src/AI/Providers/OllamaProvider.js +249 -0
  28. package/src/AI/Providers/OllamaTurboProvider.js +32 -0
  29. package/src/AI/Providers/OnnProvider.js +46 -0
  30. package/src/AI/Providers/OpenAIProvider.js +471 -0
  31. package/src/AI/Support/AudioNormalizer.js +37 -0
  32. package/src/AI/Support/ChatNormalizer.js +42 -0
  33. package/src/AI/Support/Document.js +77 -0
  34. package/src/AI/Support/DocumentAttachmentMapper.js +101 -0
  35. package/src/AI/Support/EmbeddingsNormalizer.js +30 -0
  36. package/src/AI/Support/Exceptions/ProviderError.js +22 -0
  37. package/src/AI/Support/FileSecurity.js +56 -0
  38. package/src/AI/Support/ImageNormalizer.js +62 -0
  39. package/src/AI/Support/JsonSchemaValidator.js +73 -0
  40. package/src/AI/Support/Message.js +40 -0
  41. package/src/AI/Support/StreamChunk.js +45 -0
  42. package/src/AI/Support/ToolChatRunner.js +160 -0
  43. package/src/AI/Support/ToolRegistry.js +62 -0
  44. package/src/AI/Tools/SystemInfoTool.js +25 -0
  45. package/src/index.js +67 -1
  46. package/types/index.d.ts +326 -0
@@ -515,6 +515,114 @@ const db = new DatabaseConnection({
515
515
 
516
516
  ---
517
517
 
518
+ ## AiBridgeManager
519
+
520
+ > Since v8.0.0
521
+
522
+ ### Constructor
523
+
524
+ ```javascript
525
+ const { AiBridgeManager } = require('outlet-orm');
526
+ const ai = new AiBridgeManager(config); // From config/aibridge.js or inline
527
+ ```
528
+
529
+ ### Methods
530
+
531
+ | Method | Returns | Description |
532
+ |--------|---------|-------------|
533
+ |`chat(provider, messages, opts?)`| `{ text, tool_calls, raw }` | Send chat request |
534
+ |`stream(provider, messages, opts?)`| `AsyncGenerator<StreamChunk>` | SSE/NDJSON stream |
535
+ |`streamEvents(provider, messages, opts?)`| `AsyncGenerator<{type, data}>` | Structured stream events |
536
+ |`embeddings(provider, inputs, opts?)`| `{ vectors, usage, raw }` | Generate embeddings |
537
+ |`image(provider, prompt, opts?)`| `{ url, b64_json, raw }` | Generate image |
538
+ |`tts(provider, text, opts?)`| `{ audio, mime }` | Text-to-speech |
539
+ |`stt(provider, filePath, opts?)`| `{ text }` | Speech-to-text |
540
+ |`models(provider)`| `Array<{id, ...}>` | List available models |
541
+ |`model(provider, id)`| `Object` | Get single model info |
542
+ |`text()`| `TextBuilder` | Fluent text builder |
543
+ |`chatWithTools(provider, messages, opts?)`| `{ text, raw }` | Chat with tool calling loop |
544
+ |`registerTool(tool)`| `void` | Register a custom tool |
545
+ |`registerProvider(name, provider)`| `void` | Register a custom provider |
546
+ |`provider(name)`| `Provider` | Get registered provider |
547
+ |`tool(name)`| `ToolContract` | Get registered tool |
548
+ |`tools()`| `Array<ToolContract>` | Get all tools |
549
+
550
+ ---
551
+
552
+ ## TextBuilder
553
+
554
+ | Method | Returns | Description |
555
+ |--------|---------|-------------|
556
+ |`.using(provider, model)`| `this` | Set provider and model |
557
+ |`.withPrompt(text, attachments?)`| `this` | Add user message |
558
+ |`.withSystemPrompt(text)`| `this` | Set system prompt |
559
+ |`.withMaxTokens(n)`| `this` | Max tokens limit |
560
+ |`.usingTemperature(t)`| `this` | Temperature (0–2) |
561
+ |`.usingTopP(p)`| `this` | Top-p sampling |
562
+ |`.withApiKey(key)`| `this` | Override API key |
563
+ |`.withEndpoint(url)`| `this` | Override endpoint |
564
+ |`.withBaseUrl(url)`| `this` | Override base URL |
565
+ |`.withAuthHeader(header, prefix?)`| `this` | Override auth header |
566
+ |`.withExtraHeaders(headers)`| `this` | Extra HTTP headers |
567
+ |`.asText()`| `{ text, raw, usage, finish_reason }` | Text response |
568
+ |`.asStream()`| `AsyncGenerator<StreamChunk>` | Streaming response |
569
+ |`.asRaw()`| `Object` | Raw provider response |
570
+
571
+ ---
572
+
573
+ ## AIQueryBuilder
574
+
575
+ | Method | Returns | Description |
576
+ |--------|---------|-------------|
577
+ |`using(provider, model)`| `this` | Set LLM provider |
578
+ |`safeMode(bool)`| `this` | Restrict to SELECT/WITH |
579
+ |`query(question)`| `{ sql, params, results, explanation }` | NL → SQL + execute |
580
+ |`toSql(question)`| `{ sql, params, explanation }` | NL → SQL only |
581
+
582
+ ---
583
+
584
+ ## AISeeder
585
+
586
+ | Method | Returns | Description |
587
+ |--------|---------|-------------|
588
+ |`using(provider, model)`| `this` | Set LLM provider |
589
+ |`seed(table, count, ctx)`| `{ records, inserted }` | Generate + insert |
590
+ |`generate(table, count, ctx)`| `Array<Object>` | Preview only |
591
+
592
+ ---
593
+
594
+ ## AIQueryOptimizer
595
+
596
+ | Method | Returns | Description |
597
+ |--------|---------|-------------|
598
+ |`using(provider, model)`| `this` | Set LLM provider |
599
+ |`optimize(sql)`| `{ original, optimized, suggestions, indexes, explanation }` | Analyze + rewrite |
600
+ |`explain(sql)`| `{ plan, analysis }` | EXPLAIN + LLM analysis |
601
+
602
+ ---
603
+
604
+ ## AIPromptEnhancer
605
+
606
+ | Method | Returns | Description |
607
+ |--------|---------|-------------|
608
+ |`using(provider, model)`| `this` | Set LLM provider |
609
+ |`generateSchema(description)`| `{ tables, relations, seedHints }` | Schema from description |
610
+ |`generateModelCode(table, schema, rels)`| `string` | Model class code |
611
+ |`generateMigrationCode(table, schema)`| `string` | Migration class code |
612
+
613
+ ---
614
+
615
+ ## AISafetyGuardrails (Static)
616
+
617
+ | Method | Returns | Description |
618
+ |--------|---------|-------------|
619
+ |`detectAgent()`| `{ detected, agentName }` | Detect AI agent |
620
+ |`isDestructiveCommand(cmd)`| `boolean` | Check if destructive |
621
+ |`validateDestructiveAction(cmd, flags)`| `{ allowed, message }` | Validate with consent |
622
+ |`CONSENT_ENV_VAR`| `string` | Consent env var name |
623
+
624
+ ---
625
+
518
626
  ## References
519
627
 
520
628
  - <https://github.com/omgbwa-yasse/outlet-orm>
@@ -300,6 +300,70 @@ const native = await db.execute(
300
300
 
301
301
  ---
302
302
 
303
+ ## AI Query Builder — Natural Language to SQL
304
+
305
+ > Since v8.0.0
306
+
307
+ Convert natural language into SQL queries using any LLM provider via AiBridge.
308
+
309
+ ```javascript
310
+ const { AiBridgeManager, AIQueryBuilder, DatabaseConnection } = require('outlet-orm');
311
+
312
+ const ai = new AiBridgeManager({ providers: { openai: { api_key: process.env.OPENAI_API_KEY, model: 'gpt-4o-mini' } } });
313
+ const db = new DatabaseConnection();
314
+ const qb = new AIQueryBuilder(ai, db);
315
+
316
+ // Convert and execute
317
+ const result = await qb.query('How many users signed up last month?');
318
+ console.log(result.sql); // SELECT COUNT(*) ...
319
+ console.log(result.results); // [{ count: 42 }]
320
+
321
+ // Generate SQL without executing
322
+ const { sql } = await qb.toSql('Find duplicate emails');
323
+
324
+ // Use a specific provider
325
+ const r = await qb.using('claude', 'claude-sonnet-4-20250514')
326
+ .query('List users without orders');
327
+
328
+ // Disable safe mode (allow writes)
329
+ qb.safeMode(false);
330
+ ```
331
+
332
+ ### AI Query Builder Methods
333
+
334
+ | Method | Returns | Description |
335
+ |--------|---------|-------------|
336
+ |`using(provider, model)`| `this` | Set LLM provider |
337
+ |`safeMode(bool)`| `this` | Restrict to SELECT/WITH (default: `true`) |
338
+ |`query(question)`| `{ sql, params, results, explanation }` | NL → SQL + execute |
339
+ |`toSql(question)`| `{ sql, params, explanation }` | NL → SQL only |
340
+
341
+ See [AI.md](AI.md) for full details.
342
+
343
+ ---
344
+
345
+ ## AI Query Optimizer
346
+
347
+ > Since v8.0.0
348
+
349
+ Analyze and optimize SQL queries with AI.
350
+
351
+ ```javascript
352
+ const { AIQueryOptimizer } = require('outlet-orm');
353
+
354
+ const optimizer = new AIQueryOptimizer(ai, db);
355
+ const result = await optimizer.optimize('SELECT * FROM orders WHERE ...');
356
+ console.log(result.optimized); // Rewritten SQL
357
+ console.log(result.suggestions); // [{ type, description, impact }]
358
+ console.log(result.indexes); // ['CREATE INDEX ...']
359
+
360
+ const { plan, analysis } = await optimizer.explain('SELECT ...');
361
+ ```
362
+
363
+ See [AI.md](AI.md) for full details.
364
+
365
+ ---
366
+
303
367
  ## Query Builder Methods Summary
304
368
 
305
369
  | Method | Description |
@@ -96,3 +96,50 @@ outlet-migrate seed
96
96
  - Control FK order explicitly in`DatabaseSeeder`.
97
97
  - Keep heavy bulk data in dedicated import scripts.
98
98
  - Prefer unique constraints to prevent duplicate seed data.
99
+
100
+ ---
101
+
102
+ ## AI Seeder — LLM-Powered Data Generation
103
+
104
+ > Since v8.0.0
105
+
106
+ Generate realistic domain-specific seed data using AI instead of generic lorem ipsum.
107
+
108
+ ```javascript
109
+ const { AiBridgeManager, AISeeder, DatabaseConnection } = require('outlet-orm');
110
+
111
+ const ai = new AiBridgeManager({
112
+ providers: { openai: { api_key: process.env.OPENAI_API_KEY, model: 'gpt-4o-mini' } }
113
+ });
114
+ const seeder = new AISeeder(ai, new DatabaseConnection());
115
+
116
+ // Generate and insert 10 realistic user records
117
+ const { records, inserted } = await seeder.seed('users', 10, {
118
+ domain: 'e-commerce',
119
+ locale: 'fr_FR',
120
+ description: 'An online fashion store'
121
+ });
122
+
123
+ // Preview without inserting
124
+ const preview = await seeder.generate('products', 5, {
125
+ domain: 'electronics'
126
+ });
127
+ ```
128
+
129
+ ### AI Seeder API
130
+
131
+ | Method | Returns | Description |
132
+ |--------|---------|-------------|
133
+ |`using(provider, model)`| `this` | Set LLM provider |
134
+ |`seed(table, count, context)`| `{ records, inserted }` | Generate + insert |
135
+ |`generate(table, count, context)`| `Array<Object>` | Generate only (preview) |
136
+
137
+ ### Context Options
138
+
139
+ | Option | Type | Description |
140
+ |--------|------|-------------|
141
+ | `domain` | `string` | Business domain (`'e-commerce'`, `'healthcare'`, `'finance'`) |
142
+ | `locale` | `string` | Locale for names/addresses (`'fr_FR'`, `'ja_JP'`, `'pt_BR'`) |
143
+ | `description` | `string` | Detailed description for better data quality |
144
+
145
+ See [AI.md](AI.md) for full details.
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: outlet-orm-best-practices
3
- description: Outlet ORM is a Laravel Eloquent-inspired ORM for Node.js with MySQL, PostgreSQL, and SQLite support. Use this skill when working with Outlet ORM models, queries, relationships, migrations, backup, and database operations. v6.0.0 adds a full Backup module (BackupManager, BackupScheduler, AES-256-GCM encryption, TCP daemon).
3
+ description: Outlet ORM is a Laravel Eloquent-inspired ORM for Node.js with MySQL, PostgreSQL, and SQLite support. Use this skill when working with Outlet ORM models, queries, relationships, migrations, backup, AI integration (AiBridge multi-provider LLM, AI Query Builder, AI Seeder, AI Optimizer, MCP Server) and database operations.
4
4
  license: MIT
5
5
  metadata:
6
6
  author: omgbwa-yasse
7
- version: "6.0.0"
7
+ version: "9.0.0"
8
8
  source: https://github.com/omgbwa-yasse/outlet-orm
9
9
  npm: https://www.npmjs.com/package/outlet-orm
10
10
  ---
@@ -13,11 +13,15 @@ npm: https://www.npmjs.com/package/outlet-orm
13
13
 
14
14
  Comprehensive guide for using Outlet ORM - a Laravel Eloquent-inspired ORM for Node.js/TypeScript with support for MySQL, PostgreSQL, and SQLite.
15
15
 
16
- > 🆕 **v7.0.0**: AI IntegrationMCP Server (Model Context Protocol), AI Safety Guardrails, Prompt-based project initialization. See [AI.md](AI.md).
16
+ > 🆕 **v9.0.0**: Complete AI documentationAiBridge multi-provider LLM, AI Query Builder, AI Seeder, AI Optimizer, AI Prompt Enhancer, AI Safety Guardrails. See [AI.md](AI.md).
17
+ >
18
+ > 🔖 **v8.0.0**: AiBridge multi-provider LLM abstraction (9 providers), AI Query Builder, AI Seeder, AI Query Optimizer, AI Prompt Enhancer.
19
+ >
20
+ > 🔖 **v7.0.0**: AI Integration — MCP Server (Model Context Protocol), AI Safety Guardrails, Prompt-based project initialization.
17
21
  >
18
22
  > 🔖 **v6.5.0**: Accessors & Mutators, firstOrCreate/firstOrNew/updateOrCreate, upsert, Observer pattern, cursor/stream.
19
23
  >
20
- > 🔖 **v6.0.0**: Full Backup module — `BackupManager`, `BackupScheduler`, AES-256-GCM `BackupEncryption`, `BackupSocketServer` TCP daemon, `BackupSocketClient` with remote restore. See [BACKUP.md](BACKUP.md).
24
+ > 🔖 **v6.0.0**: Full Backup module — `BackupManager`, `BackupScheduler`, AES-256-GCM `BackupEncryption`, `BackupSocketServer` TCP daemon. See [BACKUP.md](BACKUP.md).
21
25
  >
22
26
  > 🔖 **v5.0.0**: Full TypeScript support with Generic Model, typed Schema Builder, MigrationInterface and Copilot Skills integration.
23
27
 
@@ -33,7 +37,7 @@ Comprehensive guide for using Outlet ORM - a Laravel Eloquent-inspired ORM for N
33
37
  | **[TYPESCRIPT.md](TYPESCRIPT.md)** | TypeScript types, generics, typed models, migrations |
34
38
  | **[SECURITY.md](SECURITY.md)** | 🔐 Security best practices, authentication, authorisation |
35
39
  | **[BACKUP.md](BACKUP.md)** | 🗄️ Backups, scheduling, AES-256-GCM encryption, TCP daemon, restore |
36
- | **[AI.md](AI.md)** | 🤖 MCP Server, AI Safety Guardrails, Prompt-based Init |
40
+ | **[AI.md](AI.md)** | 🤖 AiBridge (9 LLM providers), AI Query Builder, AI Seeder, AI Optimizer, AI Prompt Enhancer, MCP Server, AI Safety Guardrails |
37
41
  | **[API.md](API.md)** | Complete API Reference |
38
42
 
39
43
  ---
@@ -52,8 +56,12 @@ Reference these guidelines when:
52
56
  - Scheduling or encrypting database backups [BACKUP.md](BACKUP.md)
53
57
  - Restoring a database from a backup file [BACKUP.md](BACKUP.md)
54
58
  - Running a long-lived backup daemon over TCP [BACKUP.md](BACKUP.md)
59
+ - Configuring LLM providers (AiBridge) [AI.md](AI.md)
60
+ - Converting natural language to SQL (AI Query Builder) [AI.md](AI.md)
61
+ - Generating realistic seed data with AI [AI.md](AI.md)
62
+ - Optimizing SQL queries with AI [AI.md](AI.md)
63
+ - Generating schemas/models/migrations from descriptions [AI.md](AI.md)
55
64
  - Exposing the ORM to AI agents via MCP [AI.md](AI.md)
56
- - Generating projects from natural language prompts [AI.md](AI.md)
57
65
  - Protecting against AI-initiated destructive operations [AI.md](AI.md)
58
66
 
59
67
  ---
@@ -194,7 +202,7 @@ outlet-migrate migrate
194
202
  | 7 | Validation & Events | MEDIUM | [ADVANCED.md](ADVANCED.md) |
195
203
  | 8 | Migrations & CLI | LOW-MEDIUM | [MIGRATIONS.md](MIGRATIONS.md) |
196
204
  | 9 | Backup & Restore | MEDIUM | [BACKUP.md](BACKUP.md) |
197
- | 10 | AI / MCP Integration | MEDIUM | [AI.md](AI.md) |
205
+ | 10 | AI / MCP Integration | MEDIUM-HIGH | [AI.md](AI.md) |
198
206
 
199
207
  ---
200
208
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "outlet-orm",
3
- "version": "7.0.0",
3
+ "version": "9.0.1",
4
4
  "description": "A Laravel Eloquent-inspired ORM for Node.js with support for MySQL, PostgreSQL, and SQLite",
5
5
  "main": "src/index.js",
6
6
  "types": "types/index.d.ts",
@@ -0,0 +1,170 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * AIPromptEnhancer
5
+ * LLM-powered enhancement of the existing regex-based PromptGenerator.
6
+ * Takes a natural language description and uses AI to generate richer schemas,
7
+ * model code, migrations, and seeders — beyond what pattern matching can do.
8
+ *
9
+ * @since 8.0.0
10
+ */
11
+ class AIPromptEnhancer {
12
+ /**
13
+ * @param {import('./AiBridgeManager')} manager
14
+ */
15
+ constructor(manager) {
16
+ this._manager = manager;
17
+ this._provider = 'openai';
18
+ this._model = 'gpt-4o-mini';
19
+ }
20
+
21
+ /**
22
+ * @param {string} provider
23
+ * @param {string} model
24
+ * @returns {this}
25
+ */
26
+ using(provider, model) {
27
+ this._provider = provider;
28
+ this._model = model;
29
+ return this;
30
+ }
31
+
32
+ /**
33
+ * Generate a full project schema from a natural language description.
34
+ * Returns tables, columns, relations, and seed hints.
35
+ * @param {string} description - e.g., "A recipe sharing app with users, recipes, ingredients, and reviews"
36
+ * @param {Object} [options={}]
37
+ * @returns {Promise<{tables: Object, relations: Array, seedHints: Object}>}
38
+ */
39
+ async generateSchema(description, options = {}) {
40
+ const systemPrompt = `You are an expert database architect. Given an application description, design a complete relational database schema.
41
+
42
+ RULES:
43
+ - Return a JSON object with:
44
+ "tables" — object where each key is a table name, value is an object with "columns" (array of "name:type:modifiers" strings, using outlet-orm format like "name:string", "email:string:unique", "user_id:foreignId", "content:text:nullable", "price:decimal(10,2)", "status:string:default(active)").
45
+ "relations" — array of objects with "type" (hasOne, hasMany, belongsTo, belongsToMany), "from", "to", and optionally "pivot" table name.
46
+ "seedHints" — object where each key is a table name, value is a short description of the kind of seed data to generate.
47
+ - Always include id, created_at, updated_at columns implicitly (don't list them).
48
+ - Use snake_case for column/table names.
49
+ - Include foreign keys where appropriate.
50
+ - Design for at least 3rd normal form.`;
51
+
52
+ const messages = [
53
+ { role: 'system', content: systemPrompt },
54
+ { role: 'user', content: `Design a database schema for: ${description}` },
55
+ ];
56
+
57
+ const res = await this._manager.chat(this._provider, messages, {
58
+ model: options.model || this._model,
59
+ temperature: 0.5,
60
+ max_tokens: 4096,
61
+ response_format: 'json',
62
+ json_schema: {
63
+ name: 'schema_design',
64
+ schema: {
65
+ type: 'object',
66
+ properties: {
67
+ tables: { type: 'object' },
68
+ relations: { type: 'array', items: { type: 'object' } },
69
+ seedHints: { type: 'object' },
70
+ },
71
+ required: ['tables'],
72
+ },
73
+ },
74
+ });
75
+
76
+ return this._extractJson(res);
77
+ }
78
+
79
+ /**
80
+ * Generate model source code for a given table schema.
81
+ * @param {string} tableName
82
+ * @param {Object} tableSchema - { columns: [...] }
83
+ * @param {Array} [relations=[]]
84
+ * @returns {Promise<string>}
85
+ */
86
+ async generateModelCode(tableName, tableSchema, relations = []) {
87
+ const systemPrompt = `You are an expert in outlet-orm (a Node.js Eloquent-inspired ORM).
88
+ Generate a complete model class for the given table. Use CommonJS (module.exports).
89
+
90
+ Example format:
91
+ const { Model } = require('outlet-orm');
92
+ class User extends Model {
93
+ static tableName = 'users';
94
+ static fillable = ['name', 'email', 'password'];
95
+ static hidden = ['password'];
96
+ static casts = { created_at: 'datetime' };
97
+ posts() { return this.hasMany('Post', 'user_id'); }
98
+ }
99
+ module.exports = User;
100
+
101
+ Include fillable, hidden (for sensitive fields), casts, and relation methods.`;
102
+
103
+ const messages = [
104
+ { role: 'system', content: systemPrompt },
105
+ {
106
+ role: 'user',
107
+ content: `Generate an outlet-orm model for table "${tableName}":\nColumns: ${JSON.stringify(tableSchema.columns || [])}\nRelations: ${JSON.stringify(relations)}`,
108
+ },
109
+ ];
110
+
111
+ const res = await this._manager.chat(this._provider, messages, {
112
+ model: this._model,
113
+ temperature: 0.3,
114
+ max_tokens: 2048,
115
+ });
116
+
117
+ return res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || '';
118
+ }
119
+
120
+ /**
121
+ * Generate migration code for a given table schema.
122
+ * @param {string} tableName
123
+ * @param {Object} tableSchema
124
+ * @returns {Promise<string>}
125
+ */
126
+ async generateMigrationCode(tableName, tableSchema) {
127
+ const systemPrompt = `You are an expert in outlet-orm migrations. Generate a migration file.
128
+
129
+ Example format:
130
+ const { Migration, Schema } = require('outlet-orm');
131
+ class CreateUsersTable extends Migration {
132
+ async up(schema) {
133
+ await schema.create('users', (table) => {
134
+ table.increments('id');
135
+ table.string('name');
136
+ table.string('email').unique();
137
+ table.timestamps();
138
+ });
139
+ }
140
+ async down(schema) {
141
+ await schema.dropIfExists('users');
142
+ }
143
+ }
144
+ module.exports = CreateUsersTable;
145
+
146
+ Use proper column types: string, text, integer, bigInteger, decimal, boolean, date, datetime, timestamp, json, foreignId.`;
147
+
148
+ const messages = [
149
+ { role: 'system', content: systemPrompt },
150
+ { role: 'user', content: `Generate a migration for table "${tableName}":\nColumns: ${JSON.stringify(tableSchema.columns || [])}` },
151
+ ];
152
+
153
+ const res = await this._manager.chat(this._provider, messages, {
154
+ model: this._model,
155
+ temperature: 0.2,
156
+ max_tokens: 2048,
157
+ });
158
+
159
+ return res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || '';
160
+ }
161
+
162
+ /** @private */
163
+ _extractJson(res) {
164
+ let content = res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || res?.message?.content || '';
165
+ if (typeof content !== 'string') content = JSON.stringify(content);
166
+ try { return JSON.parse(content); } catch { return { tables: {}, relations: [], seedHints: {} }; }
167
+ }
168
+ }
169
+
170
+ module.exports = AIPromptEnhancer;