@ai-orchestration/core 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 (199) hide show
  1. package/.eslintrc.json +27 -0
  2. package/README.md +516 -0
  3. package/dist/core/errors.d.ts +21 -0
  4. package/dist/core/errors.d.ts.map +1 -0
  5. package/dist/core/errors.js +38 -0
  6. package/dist/core/errors.js.map +1 -0
  7. package/dist/core/interfaces.d.ts +87 -0
  8. package/dist/core/interfaces.d.ts.map +1 -0
  9. package/dist/core/interfaces.js +5 -0
  10. package/dist/core/interfaces.js.map +1 -0
  11. package/dist/core/orchestrator.d.ts +55 -0
  12. package/dist/core/orchestrator.d.ts.map +1 -0
  13. package/dist/core/orchestrator.js +147 -0
  14. package/dist/core/orchestrator.js.map +1 -0
  15. package/dist/core/types.d.ts +72 -0
  16. package/dist/core/types.d.ts.map +1 -0
  17. package/dist/core/types.js +5 -0
  18. package/dist/core/types.js.map +1 -0
  19. package/dist/factory/index.d.ts +14 -0
  20. package/dist/factory/index.d.ts.map +1 -0
  21. package/dist/factory/index.js +184 -0
  22. package/dist/factory/index.js.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +15 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/providers/base.d.ts +30 -0
  28. package/dist/providers/base.d.ts.map +1 -0
  29. package/dist/providers/base.js +31 -0
  30. package/dist/providers/base.js.map +1 -0
  31. package/dist/providers/cerebras.d.ts +26 -0
  32. package/dist/providers/cerebras.d.ts.map +1 -0
  33. package/dist/providers/cerebras.js +190 -0
  34. package/dist/providers/cerebras.js.map +1 -0
  35. package/dist/providers/gemini.d.ts +26 -0
  36. package/dist/providers/gemini.d.ts.map +1 -0
  37. package/dist/providers/gemini.js +181 -0
  38. package/dist/providers/gemini.js.map +1 -0
  39. package/dist/providers/groq.d.ts +26 -0
  40. package/dist/providers/groq.d.ts.map +1 -0
  41. package/dist/providers/groq.js +225 -0
  42. package/dist/providers/groq.js.map +1 -0
  43. package/dist/providers/index.d.ts +15 -0
  44. package/dist/providers/index.d.ts.map +1 -0
  45. package/dist/providers/index.js +10 -0
  46. package/dist/providers/index.js.map +1 -0
  47. package/dist/providers/local.d.ts +27 -0
  48. package/dist/providers/local.d.ts.map +1 -0
  49. package/dist/providers/local.js +198 -0
  50. package/dist/providers/local.js.map +1 -0
  51. package/dist/providers/openrouter.d.ts +26 -0
  52. package/dist/providers/openrouter.d.ts.map +1 -0
  53. package/dist/providers/openrouter.js +172 -0
  54. package/dist/providers/openrouter.js.map +1 -0
  55. package/dist/strategies/base.d.ts +16 -0
  56. package/dist/strategies/base.d.ts.map +1 -0
  57. package/dist/strategies/base.js +21 -0
  58. package/dist/strategies/base.js.map +1 -0
  59. package/dist/strategies/fallback.d.ts +14 -0
  60. package/dist/strategies/fallback.d.ts.map +1 -0
  61. package/dist/strategies/fallback.js +29 -0
  62. package/dist/strategies/fallback.js.map +1 -0
  63. package/dist/strategies/health-aware.d.ts +20 -0
  64. package/dist/strategies/health-aware.d.ts.map +1 -0
  65. package/dist/strategies/health-aware.js +106 -0
  66. package/dist/strategies/health-aware.js.map +1 -0
  67. package/dist/strategies/index.d.ts +14 -0
  68. package/dist/strategies/index.d.ts.map +1 -0
  69. package/dist/strategies/index.js +10 -0
  70. package/dist/strategies/index.js.map +1 -0
  71. package/dist/strategies/priority.d.ts +18 -0
  72. package/dist/strategies/priority.d.ts.map +1 -0
  73. package/dist/strategies/priority.js +35 -0
  74. package/dist/strategies/priority.js.map +1 -0
  75. package/dist/strategies/round-robin.d.ts +10 -0
  76. package/dist/strategies/round-robin.d.ts.map +1 -0
  77. package/dist/strategies/round-robin.js +21 -0
  78. package/dist/strategies/round-robin.js.map +1 -0
  79. package/dist/strategies/weighted.d.ts +20 -0
  80. package/dist/strategies/weighted.d.ts.map +1 -0
  81. package/dist/strategies/weighted.js +58 -0
  82. package/dist/strategies/weighted.js.map +1 -0
  83. package/docs/ARCHITECTURE.md +126 -0
  84. package/docs/CHANGELOG.md +30 -0
  85. package/docs/CONTRIBUTING.md +198 -0
  86. package/examples/basic.ts +58 -0
  87. package/examples/chat-app/README.md +146 -0
  88. package/examples/chat-app/config.json +34 -0
  89. package/examples/chat-app/index.ts +330 -0
  90. package/examples/chat-app/package-lock.json +570 -0
  91. package/examples/chat-app/package.json +20 -0
  92. package/examples/config.example.json +42 -0
  93. package/examples/strategies.ts +112 -0
  94. package/examples/test-local.ts +150 -0
  95. package/examples/test-mock.ts +172 -0
  96. package/package/.eslintrc.json +27 -0
  97. package/package/CHANGELOG.md +31 -0
  98. package/package/CONTRIBUTING.md +156 -0
  99. package/package/PUBLISHING.md +213 -0
  100. package/package/README.md +515 -0
  101. package/package/dist/core/errors.d.ts +21 -0
  102. package/package/dist/core/errors.d.ts.map +1 -0
  103. package/package/dist/core/errors.js +38 -0
  104. package/package/dist/core/errors.js.map +1 -0
  105. package/package/dist/core/interfaces.d.ts +87 -0
  106. package/package/dist/core/interfaces.d.ts.map +1 -0
  107. package/package/dist/core/interfaces.js +5 -0
  108. package/package/dist/core/interfaces.js.map +1 -0
  109. package/package/dist/core/orchestrator.d.ts +55 -0
  110. package/package/dist/core/orchestrator.d.ts.map +1 -0
  111. package/package/dist/core/orchestrator.js +147 -0
  112. package/package/dist/core/orchestrator.js.map +1 -0
  113. package/package/dist/core/types.d.ts +72 -0
  114. package/package/dist/core/types.d.ts.map +1 -0
  115. package/package/dist/core/types.js +5 -0
  116. package/package/dist/core/types.js.map +1 -0
  117. package/package/dist/factory/index.d.ts +14 -0
  118. package/package/dist/factory/index.d.ts.map +1 -0
  119. package/package/dist/factory/index.js +184 -0
  120. package/package/dist/factory/index.js.map +1 -0
  121. package/package/dist/index.d.ts +14 -0
  122. package/package/dist/index.d.ts.map +1 -0
  123. package/package/dist/index.js +15 -0
  124. package/package/dist/index.js.map +1 -0
  125. package/package/dist/providers/base.d.ts +30 -0
  126. package/package/dist/providers/base.d.ts.map +1 -0
  127. package/package/dist/providers/base.js +31 -0
  128. package/package/dist/providers/base.js.map +1 -0
  129. package/package/dist/providers/cerebras.d.ts +26 -0
  130. package/package/dist/providers/cerebras.d.ts.map +1 -0
  131. package/package/dist/providers/cerebras.js +190 -0
  132. package/package/dist/providers/cerebras.js.map +1 -0
  133. package/package/dist/providers/gemini.d.ts +26 -0
  134. package/package/dist/providers/gemini.d.ts.map +1 -0
  135. package/package/dist/providers/gemini.js +181 -0
  136. package/package/dist/providers/gemini.js.map +1 -0
  137. package/package/dist/providers/groq.d.ts +26 -0
  138. package/package/dist/providers/groq.d.ts.map +1 -0
  139. package/package/dist/providers/groq.js +225 -0
  140. package/package/dist/providers/groq.js.map +1 -0
  141. package/package/dist/providers/index.d.ts +15 -0
  142. package/package/dist/providers/index.d.ts.map +1 -0
  143. package/package/dist/providers/index.js +10 -0
  144. package/package/dist/providers/index.js.map +1 -0
  145. package/package/dist/providers/local.d.ts +27 -0
  146. package/package/dist/providers/local.d.ts.map +1 -0
  147. package/package/dist/providers/local.js +198 -0
  148. package/package/dist/providers/local.js.map +1 -0
  149. package/package/dist/providers/openrouter.d.ts +26 -0
  150. package/package/dist/providers/openrouter.d.ts.map +1 -0
  151. package/package/dist/providers/openrouter.js +172 -0
  152. package/package/dist/providers/openrouter.js.map +1 -0
  153. package/package/dist/strategies/base.d.ts +16 -0
  154. package/package/dist/strategies/base.d.ts.map +1 -0
  155. package/package/dist/strategies/base.js +21 -0
  156. package/package/dist/strategies/base.js.map +1 -0
  157. package/package/dist/strategies/fallback.d.ts +14 -0
  158. package/package/dist/strategies/fallback.d.ts.map +1 -0
  159. package/package/dist/strategies/fallback.js +29 -0
  160. package/package/dist/strategies/fallback.js.map +1 -0
  161. package/package/dist/strategies/health-aware.d.ts +20 -0
  162. package/package/dist/strategies/health-aware.d.ts.map +1 -0
  163. package/package/dist/strategies/health-aware.js +106 -0
  164. package/package/dist/strategies/health-aware.js.map +1 -0
  165. package/package/dist/strategies/index.d.ts +14 -0
  166. package/package/dist/strategies/index.d.ts.map +1 -0
  167. package/package/dist/strategies/index.js +10 -0
  168. package/package/dist/strategies/index.js.map +1 -0
  169. package/package/dist/strategies/priority.d.ts +18 -0
  170. package/package/dist/strategies/priority.d.ts.map +1 -0
  171. package/package/dist/strategies/priority.js +35 -0
  172. package/package/dist/strategies/priority.js.map +1 -0
  173. package/package/dist/strategies/round-robin.d.ts +10 -0
  174. package/package/dist/strategies/round-robin.d.ts.map +1 -0
  175. package/package/dist/strategies/round-robin.js +21 -0
  176. package/package/dist/strategies/round-robin.js.map +1 -0
  177. package/package/dist/strategies/weighted.d.ts +20 -0
  178. package/package/dist/strategies/weighted.d.ts.map +1 -0
  179. package/package/dist/strategies/weighted.js +58 -0
  180. package/package/dist/strategies/weighted.js.map +1 -0
  181. package/package/docs/ARCHITECTURE.md +127 -0
  182. package/package/examples/basic.ts +58 -0
  183. package/package/examples/chat-app/README.md +146 -0
  184. package/package/examples/chat-app/config.json +34 -0
  185. package/package/examples/chat-app/index.ts +330 -0
  186. package/package/examples/chat-app/package-lock.json +570 -0
  187. package/package/examples/chat-app/package.json +20 -0
  188. package/package/examples/config.example.json +42 -0
  189. package/package/examples/strategies.ts +112 -0
  190. package/package/examples/test-local.ts +150 -0
  191. package/package/examples/test-mock.ts +172 -0
  192. package/package/package.json +62 -0
  193. package/package/scripts/check-types.ts +15 -0
  194. package/package/scripts/link.sh +30 -0
  195. package/package/scripts/pack.sh +36 -0
  196. package/package.json +62 -0
  197. package/scripts/check-types.ts +15 -0
  198. package/scripts/link.sh +30 -0
  199. package/scripts/pack.sh +36 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Examples of different strategies
3
+ */
4
+
5
+ import { createOrchestrator } from '../src/index.js';
6
+
7
+ // Example 1: Priority Strategy
8
+ export function createPriorityOrchestrator() {
9
+ return createOrchestrator({
10
+ providers: [
11
+ {
12
+ id: 'groq-1',
13
+ type: 'groq',
14
+ apiKey: process.env.GROQ_API_KEY || '',
15
+ priority: 1,
16
+ },
17
+ {
18
+ id: 'openrouter-1',
19
+ type: 'openrouter',
20
+ apiKey: process.env.OPENROUTER_API_KEY || '',
21
+ priority: 2,
22
+ },
23
+ ],
24
+ strategy: {
25
+ type: 'priority',
26
+ priorities: {
27
+ 'groq-1': 1,
28
+ 'openrouter-1': 2,
29
+ },
30
+ },
31
+ });
32
+ }
33
+
34
+ // Example 2: Fallback Strategy
35
+ export function createFallbackOrchestrator() {
36
+ return createOrchestrator({
37
+ providers: [
38
+ {
39
+ id: 'groq-1',
40
+ type: 'groq',
41
+ apiKey: process.env.GROQ_API_KEY || '',
42
+ },
43
+ {
44
+ id: 'openrouter-1',
45
+ type: 'openrouter',
46
+ apiKey: process.env.OPENROUTER_API_KEY || '',
47
+ },
48
+ {
49
+ id: 'gemini-1',
50
+ type: 'gemini',
51
+ apiKey: process.env.GEMINI_API_KEY || '',
52
+ },
53
+ ],
54
+ strategy: {
55
+ type: 'fallback',
56
+ order: ['groq-1', 'openrouter-1', 'gemini-1'],
57
+ },
58
+ });
59
+ }
60
+
61
+ // Example 3: Weighted Strategy (Load Balancing)
62
+ export function createWeightedOrchestrator() {
63
+ return createOrchestrator({
64
+ providers: [
65
+ {
66
+ id: 'groq-1',
67
+ type: 'groq',
68
+ apiKey: process.env.GROQ_API_KEY || '',
69
+ weight: 0.7,
70
+ },
71
+ {
72
+ id: 'openrouter-1',
73
+ type: 'openrouter',
74
+ apiKey: process.env.OPENROUTER_API_KEY || '',
75
+ weight: 0.3,
76
+ },
77
+ ],
78
+ strategy: {
79
+ type: 'weighted',
80
+ weights: {
81
+ 'groq-1': 0.7,
82
+ 'openrouter-1': 0.3,
83
+ },
84
+ },
85
+ });
86
+ }
87
+
88
+ // Example 4: Health-Aware Strategy
89
+ export function createHealthAwareOrchestrator() {
90
+ return createOrchestrator({
91
+ providers: [
92
+ {
93
+ id: 'groq-1',
94
+ type: 'groq',
95
+ apiKey: process.env.GROQ_API_KEY || '',
96
+ },
97
+ {
98
+ id: 'openrouter-1',
99
+ type: 'openrouter',
100
+ apiKey: process.env.OPENROUTER_API_KEY || '',
101
+ },
102
+ ],
103
+ strategy: {
104
+ type: 'health-aware',
105
+ preferLowLatency: true,
106
+ minHealthScore: 0.5,
107
+ },
108
+ enableHealthChecks: true,
109
+ healthCheckInterval: 30000, // 30 seconds
110
+ });
111
+ }
112
+
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Local test script
3
+ * Run with: npm run test:local
4
+ * or: tsx examples/test-local.ts
5
+ */
6
+
7
+ import { createOrchestrator } from '../src/index.js';
8
+
9
+ async function main() {
10
+ console.log('🚀 Iniciando prueba del framework...\n');
11
+
12
+ // Verificar variables de entorno
13
+ const hasGroq = !!process.env.GROQ_API_KEY;
14
+ const hasOpenRouter = !!process.env.OPENROUTER_API_KEY;
15
+ const hasGemini = !!process.env.GEMINI_API_KEY;
16
+
17
+ console.log('📋 Estado de API Keys:');
18
+ console.log(` Groq: ${hasGroq ? '✅' : '❌'}`);
19
+ console.log(` OpenRouter: ${hasOpenRouter ? '✅' : '❌'}`);
20
+ console.log(` Gemini: ${hasGemini ? '✅' : '❌'}\n`);
21
+
22
+ if (!hasGroq && !hasOpenRouter && !hasGemini) {
23
+ console.log('⚠️ No se encontraron API keys.');
24
+ console.log(' Configura las variables de entorno:');
25
+ console.log(' export GROQ_API_KEY="tu-key"');
26
+ console.log(' export OPENROUTER_API_KEY="tu-key"');
27
+ console.log(' export GEMINI_API_KEY="tu-key"\n');
28
+ console.log(' O crea un archivo .env con:');
29
+ console.log(' GROQ_API_KEY=tu-key');
30
+ console.log(' OPENROUTER_API_KEY=tu-key');
31
+ console.log(' GEMINI_API_KEY=tu-key\n');
32
+ return;
33
+ }
34
+
35
+ // Crear configuración dinámica basada en las keys disponibles
36
+ const providers: any[] = [];
37
+
38
+ if (hasGroq) {
39
+ providers.push({
40
+ id: 'groq-1',
41
+ type: 'groq',
42
+ apiKey: process.env.GROQ_API_KEY,
43
+ model: 'llama-3.1-70b-versatile',
44
+ });
45
+ }
46
+
47
+ if (hasOpenRouter) {
48
+ providers.push({
49
+ id: 'openrouter-1',
50
+ type: 'openrouter',
51
+ apiKey: process.env.OPENROUTER_API_KEY,
52
+ model: 'openai/gpt-3.5-turbo',
53
+ });
54
+ }
55
+
56
+ if (hasGemini) {
57
+ providers.push({
58
+ id: 'gemini-1',
59
+ type: 'gemini',
60
+ apiKey: process.env.GEMINI_API_KEY,
61
+ model: 'gemini-pro',
62
+ });
63
+ }
64
+
65
+ try {
66
+ console.log('🔧 Creando orchestrator...');
67
+ const orchestrator = createOrchestrator({
68
+ providers,
69
+ strategy: {
70
+ type: 'round-robin',
71
+ },
72
+ });
73
+
74
+ console.log(`✅ Orchestrator creado con ${providers.length} proveedor(es)\n`);
75
+
76
+ // Test 1: Chat simple
77
+ console.log('📝 Test 1: Chat simple');
78
+ console.log('─────────────────────────────────');
79
+ const messages = [
80
+ { role: 'user' as const, content: 'Di "Hola" en una sola palabra' },
81
+ ];
82
+
83
+ const startTime = Date.now();
84
+ const response = await orchestrator.chat(messages, {
85
+ temperature: 0.7,
86
+ maxTokens: 50,
87
+ });
88
+ const duration = Date.now() - startTime;
89
+
90
+ console.log(`Respuesta: ${response.content}`);
91
+ console.log(`Modelo: ${response.model || 'N/A'}`);
92
+ console.log(`Tiempo: ${duration}ms`);
93
+ if (response.usage) {
94
+ console.log(`Tokens: ${response.usage.totalTokens} (prompt: ${response.usage.promptTokens}, completion: ${response.usage.completionTokens})`);
95
+ }
96
+ console.log('');
97
+
98
+ // Test 2: Verificar salud de proveedores
99
+ console.log('🏥 Test 2: Health checks');
100
+ console.log('─────────────────────────────────');
101
+ const allProviders = orchestrator.getAllProviders();
102
+ for (const provider of allProviders) {
103
+ try {
104
+ const health = await provider.checkHealth();
105
+ console.log(`${provider.id}: ${health.healthy ? '✅' : '❌'} ${health.latency ? `(${health.latency}ms)` : ''}`);
106
+ } catch (error) {
107
+ console.log(`${provider.id}: ❌ Error - ${error instanceof Error ? error.message : String(error)}`);
108
+ }
109
+ }
110
+ console.log('');
111
+
112
+ // Test 3: Streaming (opcional, comentado por defecto)
113
+ if (process.env.TEST_STREAMING === 'true') {
114
+ console.log('🌊 Test 3: Streaming');
115
+ console.log('─────────────────────────────────');
116
+ const stream = await orchestrator.chatStream([
117
+ { role: 'user' as const, content: 'Cuenta del 1 al 5, un número por línea' },
118
+ ]);
119
+
120
+ const reader = stream.getReader();
121
+ let fullContent = '';
122
+ while (true) {
123
+ const { done, value } = await reader.read();
124
+ if (done) break;
125
+ fullContent += value.content;
126
+ process.stdout.write(value.content);
127
+ }
128
+ console.log('\n✅ Streaming completado\n');
129
+ }
130
+
131
+ // Cleanup
132
+ orchestrator.dispose();
133
+ console.log('✅ Pruebas completadas exitosamente!');
134
+
135
+ } catch (error) {
136
+ console.error('\n❌ Error durante las pruebas:');
137
+ if (error instanceof Error) {
138
+ console.error(` ${error.name}: ${error.message}`);
139
+ if (error.stack) {
140
+ console.error(` Stack: ${error.stack}`);
141
+ }
142
+ } else {
143
+ console.error(` ${String(error)}`);
144
+ }
145
+ process.exit(1);
146
+ }
147
+ }
148
+
149
+ main().catch(console.error);
150
+
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Test with mock provider (no API keys required)
3
+ * Run with: npm run test:mock
4
+ * or: tsx examples/test-mock.ts
5
+ */
6
+
7
+ import {
8
+ Orchestrator,
9
+ RoundRobinStrategy,
10
+ PriorityStrategy,
11
+ FallbackStrategy,
12
+ } from '../src/index.js';
13
+ import type { AIService, ChatMessage, ChatResponse, ChatChunk, ProviderHealth } from '../src/index.js';
14
+
15
+ // Mock provider para pruebas sin API keys
16
+ class MockProvider implements AIService {
17
+ readonly id: string;
18
+ readonly metadata = {
19
+ id: '',
20
+ name: 'Mock Provider',
21
+ };
22
+
23
+ constructor(id: string) {
24
+ this.id = id;
25
+ this.metadata.id = id;
26
+ }
27
+
28
+ async checkHealth(): Promise<ProviderHealth> {
29
+ return {
30
+ healthy: true,
31
+ latency: Math.random() * 100,
32
+ lastChecked: new Date(),
33
+ };
34
+ }
35
+
36
+ async chat(messages: ChatMessage[]): Promise<ChatResponse> {
37
+ const lastMessage = messages[messages.length - 1]?.content || '';
38
+ return {
39
+ content: `[Mock ${this.id}] Respuesta a: "${lastMessage}"`,
40
+ usage: {
41
+ promptTokens: 10,
42
+ completionTokens: 5,
43
+ totalTokens: 15,
44
+ },
45
+ model: 'mock-model',
46
+ finishReason: 'stop',
47
+ };
48
+ }
49
+
50
+ async chatStream(messages: ChatMessage[]): Promise<ReadableStream<ChatChunk>> {
51
+ const lastMessage = messages[messages.length - 1]?.content || '';
52
+ const words = `[Mock ${this.id}] Respuesta a: "${lastMessage}"`.split(' ');
53
+
54
+ return new ReadableStream({
55
+ async start(controller) {
56
+ for (const word of words) {
57
+ await new Promise((resolve) => setTimeout(resolve, 50));
58
+ controller.enqueue({
59
+ content: word + ' ',
60
+ done: false,
61
+ });
62
+ }
63
+ controller.enqueue({
64
+ content: '',
65
+ done: true,
66
+ finishReason: 'stop',
67
+ });
68
+ controller.close();
69
+ },
70
+ });
71
+ }
72
+ }
73
+
74
+ async function main() {
75
+ console.log('🧪 Prueba con proveedores Mock\n');
76
+
77
+ // Test 1: Round-Robin Strategy
78
+ console.log('📋 Test 1: Round-Robin Strategy');
79
+ console.log('─────────────────────────────────');
80
+ const roundRobinStrategy = new RoundRobinStrategy();
81
+ const orchestrator1 = new Orchestrator(roundRobinStrategy);
82
+
83
+ orchestrator1.registerProvider(new MockProvider('mock-1'));
84
+ orchestrator1.registerProvider(new MockProvider('mock-2'));
85
+ orchestrator1.registerProvider(new MockProvider('mock-3'));
86
+
87
+ for (let i = 0; i < 5; i++) {
88
+ const provider = await orchestrator1.selectProvider();
89
+ console.log(` Request ${i + 1}: ${provider?.id}`);
90
+ }
91
+ console.log('');
92
+
93
+ // Test 2: Priority Strategy
94
+ console.log('📋 Test 2: Priority Strategy');
95
+ console.log('─────────────────────────────────');
96
+ const priorityStrategy = new PriorityStrategy({
97
+ priorities: {
98
+ 'mock-1': 1,
99
+ 'mock-2': 2,
100
+ 'mock-3': 3,
101
+ },
102
+ });
103
+ const orchestrator2 = new Orchestrator(priorityStrategy);
104
+
105
+ orchestrator2.registerProvider(new MockProvider('mock-1'));
106
+ orchestrator2.registerProvider(new MockProvider('mock-2'));
107
+ orchestrator2.registerProvider(new MockProvider('mock-3'));
108
+
109
+ for (let i = 0; i < 3; i++) {
110
+ const provider = await orchestrator2.selectProvider();
111
+ console.log(` Request ${i + 1}: ${provider?.id} (siempre el mismo por prioridad)`);
112
+ }
113
+ console.log('');
114
+
115
+ // Test 3: Fallback Strategy
116
+ console.log('📋 Test 3: Fallback Strategy');
117
+ console.log('─────────────────────────────────');
118
+ const fallbackStrategy = new FallbackStrategy({
119
+ order: ['mock-1', 'mock-2', 'mock-3'],
120
+ });
121
+ const orchestrator3 = new Orchestrator(fallbackStrategy);
122
+
123
+ orchestrator3.registerProvider(new MockProvider('mock-1'));
124
+ orchestrator3.registerProvider(new MockProvider('mock-2'));
125
+ orchestrator3.registerProvider(new MockProvider('mock-3'));
126
+
127
+ const provider = await orchestrator3.selectProvider();
128
+ console.log(` Seleccionado: ${provider?.id} (siempre el primero de la lista)`);
129
+ console.log('');
130
+
131
+ // Test 4: Chat real con mock
132
+ console.log('📋 Test 4: Chat con Mock Provider');
133
+ console.log('─────────────────────────────────');
134
+ const orchestrator4 = new Orchestrator(new RoundRobinStrategy());
135
+ orchestrator4.registerProvider(new MockProvider('mock-1'));
136
+ orchestrator4.registerProvider(new MockProvider('mock-2'));
137
+
138
+ const response = await orchestrator4.chat([
139
+ { role: 'user', content: 'Hola, ¿cómo estás?' },
140
+ ]);
141
+
142
+ console.log(` Respuesta: ${response.content}`);
143
+ console.log(` Tokens: ${response.usage?.totalTokens}`);
144
+ console.log('');
145
+
146
+ // Test 5: Streaming con mock
147
+ console.log('📋 Test 5: Streaming con Mock Provider');
148
+ console.log('─────────────────────────────────');
149
+ const stream = await orchestrator4.chatStream([
150
+ { role: 'user', content: 'Cuenta hasta 3' },
151
+ ]);
152
+
153
+ const reader = stream.getReader();
154
+ process.stdout.write(' Stream: ');
155
+ while (true) {
156
+ const { done, value } = await reader.read();
157
+ if (done) break;
158
+ process.stdout.write(value.content);
159
+ }
160
+ console.log('\n');
161
+
162
+ // Cleanup
163
+ orchestrator1.dispose();
164
+ orchestrator2.dispose();
165
+ orchestrator3.dispose();
166
+ orchestrator4.dispose();
167
+
168
+ console.log('✅ Todas las pruebas completadas!');
169
+ }
170
+
171
+ main().catch(console.error);
172
+
@@ -0,0 +1,27 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/recommended"
6
+ ],
7
+ "parserOptions": {
8
+ "ecmaVersion": 2022,
9
+ "sourceType": "module"
10
+ },
11
+ "env": {
12
+ "node": true,
13
+ "es2022": true
14
+ },
15
+ "rules": {
16
+ "@typescript-eslint/no-unused-vars": [
17
+ "error",
18
+ {
19
+ "argsIgnorePattern": "^_",
20
+ "varsIgnorePattern": "^_"
21
+ }
22
+ ],
23
+ "@typescript-eslint/explicit-module-boundary-types": "off",
24
+ "@typescript-eslint/no-explicit-any": "warn"
25
+ }
26
+ }
27
+
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ Todos los cambios notables en este proyecto serán documentados en este archivo.
4
+
5
+ El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/),
6
+ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
7
+
8
+ ## [0.1.0] - 2024-12-XX
9
+
10
+ ### Agregado
11
+ - Framework completo de orquestación de IA
12
+ - Soporte para múltiples proveedores: Groq, OpenRouter, Gemini, Local
13
+ - 5 estrategias de selección: Round-Robin, Priority, Fallback, Weighted, Health-Aware
14
+ - Streaming nativo con ReadableStream
15
+ - Health checks automáticos con métricas de latencia
16
+ - Factory para creación declarativa
17
+ - Manejo de errores personalizado
18
+ - Validación de configuración
19
+ - Documentación completa (README, ARCHITECTURE, USAGE, CONTRIBUTING)
20
+ - Ejemplos de uso
21
+ - Tests básicos
22
+ - Compatibilidad con Node.js y Bun
23
+
24
+ ### Características Principales
25
+ - Arquitectura basada en plugins (extensible sin modificar el core)
26
+ - API declarativa y programática
27
+ - Type-safe con TypeScript
28
+ - Fallback automático entre proveedores
29
+ - Soporte para cost-aware selection
30
+ - Health-aware selection con métricas en tiempo real
31
+
@@ -0,0 +1,156 @@
1
+ # Guía de Contribución
2
+
3
+ ## Estructura del Proyecto
4
+
5
+ ```
6
+ src/
7
+ ├── core/ # Núcleo del framework (interfaces, tipos, orchestrator)
8
+ ├── providers/ # Implementaciones de proveedores
9
+ ├── strategies/ # Estrategias de selección
10
+ ├── factory/ # Factory para creación declarativa
11
+ └── index.ts # Punto de entrada principal
12
+ ```
13
+
14
+ ## Agregar un Nuevo Proveedor
15
+
16
+ 1. **Crear el archivo del proveedor** en `src/providers/`:
17
+
18
+ ```typescript
19
+ import { BaseProvider } from './base.js';
20
+ import type {
21
+ ChatMessage,
22
+ ChatOptions,
23
+ ChatResponse,
24
+ ChatChunk,
25
+ ProviderHealth,
26
+ ProviderMetadata,
27
+ } from '../core/types.js';
28
+
29
+ export interface CustomProviderConfig {
30
+ id: string;
31
+ apiKey: string;
32
+ // ... otros campos específicos
33
+ }
34
+
35
+ export class CustomProvider extends BaseProvider {
36
+ readonly id: string;
37
+ readonly metadata: ProviderMetadata;
38
+
39
+ constructor(config: CustomProviderConfig) {
40
+ super();
41
+ // Inicialización
42
+ }
43
+
44
+ async checkHealth(): Promise<ProviderHealth> {
45
+ // Implementar health check
46
+ }
47
+
48
+ async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse> {
49
+ // Implementar chat
50
+ }
51
+
52
+ async chatStream(messages: ChatMessage[], options?: ChatOptions): Promise<ReadableStream<ChatChunk>> {
53
+ // Implementar streaming
54
+ }
55
+
56
+ protected formatMessages(messages: ChatMessage[]): unknown {
57
+ // Convertir formato estándar a formato del proveedor
58
+ }
59
+
60
+ protected parseResponse(response: unknown): ChatResponse {
61
+ // Convertir respuesta a formato estándar
62
+ }
63
+
64
+ protected parseStream(stream: ReadableStream<unknown>): ReadableStream<ChatChunk> {
65
+ // Convertir stream a formato estándar
66
+ }
67
+ }
68
+ ```
69
+
70
+ 2. **Exportar en `src/providers/index.ts`**:
71
+
72
+ ```typescript
73
+ export { CustomProvider } from './custom.js';
74
+ export type { CustomProviderConfig } from './custom.js';
75
+ ```
76
+
77
+ 3. **Registrar en `src/factory/index.ts`**:
78
+
79
+ ```typescript
80
+ import { CustomProvider, type CustomProviderConfig } from '../providers/index.js';
81
+
82
+ // En la función createProvider:
83
+ case 'custom':
84
+ return new CustomProvider({
85
+ id,
86
+ ...(rest as CustomProviderConfig),
87
+ } as CustomProviderConfig);
88
+ ```
89
+
90
+ ## Agregar una Nueva Estrategia
91
+
92
+ 1. **Crear el archivo de la estrategia** en `src/strategies/`:
93
+
94
+ ```typescript
95
+ import { BaseStrategy } from './base.js';
96
+ import type { AIService, SelectionContext } from '../core/interfaces.js';
97
+
98
+ export interface CustomStrategyConfig {
99
+ // Configuración específica
100
+ }
101
+
102
+ export class CustomStrategy extends BaseStrategy {
103
+ constructor(config?: CustomStrategyConfig) {
104
+ super();
105
+ // Inicialización
106
+ }
107
+
108
+ async select(
109
+ providers: AIService[],
110
+ context?: SelectionContext
111
+ ): Promise<AIService | null> {
112
+ // Implementar lógica de selección
113
+ }
114
+
115
+ update?(provider: AIService, success: boolean, metadata?: unknown): void {
116
+ // Opcional: actualizar estado interno
117
+ }
118
+ }
119
+ ```
120
+
121
+ 2. **Exportar en `src/strategies/index.ts`**
122
+
123
+ 3. **Registrar en `src/factory/index.ts`**
124
+
125
+ ## Convenciones de Código
126
+
127
+ - **TypeScript estricto**: Usar tipos explícitos
128
+ - **Nombres descriptivos**: Variables y funciones con nombres claros
129
+ - **Documentación**: JSDoc para funciones públicas
130
+ - **Manejo de errores**: Usar clases de error personalizadas
131
+ - **Tests**: Agregar tests para nuevas funcionalidades
132
+
133
+ ## Testing
134
+
135
+ Los tests están en `tests/`. Usar Bun test runner:
136
+
137
+ ```bash
138
+ bun test tests/
139
+ ```
140
+
141
+ ## Versionado
142
+
143
+ Seguir [Semantic Versioning](https://semver.org/):
144
+ - **MAJOR**: Cambios incompatibles en la API
145
+ - **MINOR**: Nueva funcionalidad compatible hacia atrás
146
+ - **PATCH**: Correcciones de bugs compatibles
147
+
148
+ ## Pull Requests
149
+
150
+ 1. Crear una rama desde `main`
151
+ 2. Implementar cambios
152
+ 3. Agregar tests
153
+ 4. Actualizar documentación si es necesario
154
+ 5. Asegurar que todos los tests pasen
155
+ 6. Crear PR con descripción clara
156
+