@sparkleideas/plugins 3.0.0-alpha.8

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 (80) hide show
  1. package/README.md +401 -0
  2. package/__tests__/collection-manager.test.ts +332 -0
  3. package/__tests__/dependency-graph.test.ts +434 -0
  4. package/__tests__/enhanced-plugin-registry.test.ts +488 -0
  5. package/__tests__/plugin-registry.test.ts +368 -0
  6. package/__tests__/ruvector-bridge.test.ts +2429 -0
  7. package/__tests__/ruvector-integration.test.ts +1602 -0
  8. package/__tests__/ruvector-migrations.test.ts +1099 -0
  9. package/__tests__/ruvector-quantization.test.ts +846 -0
  10. package/__tests__/ruvector-streaming.test.ts +1088 -0
  11. package/__tests__/sdk.test.ts +325 -0
  12. package/__tests__/security.test.ts +348 -0
  13. package/__tests__/utils/ruvector-test-utils.ts +860 -0
  14. package/examples/plugin-creator/index.ts +636 -0
  15. package/examples/plugin-creator/plugin-creator.test.ts +312 -0
  16. package/examples/ruvector/README.md +288 -0
  17. package/examples/ruvector/attention-patterns.ts +394 -0
  18. package/examples/ruvector/basic-usage.ts +288 -0
  19. package/examples/ruvector/docker-compose.yml +75 -0
  20. package/examples/ruvector/gnn-analysis.ts +501 -0
  21. package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
  22. package/examples/ruvector/init-db.sql +119 -0
  23. package/examples/ruvector/quantization.ts +680 -0
  24. package/examples/ruvector/self-learning.ts +447 -0
  25. package/examples/ruvector/semantic-search.ts +576 -0
  26. package/examples/ruvector/streaming-large-data.ts +507 -0
  27. package/examples/ruvector/transactions.ts +594 -0
  28. package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
  29. package/examples/ruvector-plugins/index.ts +79 -0
  30. package/examples/ruvector-plugins/intent-router.ts +354 -0
  31. package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
  32. package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
  33. package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
  34. package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
  35. package/examples/ruvector-plugins/shared/index.ts +20 -0
  36. package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
  37. package/examples/ruvector-plugins/sona-learning.ts +445 -0
  38. package/package.json +97 -0
  39. package/src/collections/collection-manager.ts +661 -0
  40. package/src/collections/index.ts +56 -0
  41. package/src/collections/official/index.ts +1040 -0
  42. package/src/core/base-plugin.ts +416 -0
  43. package/src/core/plugin-interface.ts +215 -0
  44. package/src/hooks/index.ts +685 -0
  45. package/src/index.ts +378 -0
  46. package/src/integrations/agentic-flow.ts +743 -0
  47. package/src/integrations/index.ts +88 -0
  48. package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
  49. package/src/integrations/ruvector/attention-advanced.ts +1040 -0
  50. package/src/integrations/ruvector/attention-executor.ts +782 -0
  51. package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
  52. package/src/integrations/ruvector/attention.ts +1063 -0
  53. package/src/integrations/ruvector/gnn.ts +3050 -0
  54. package/src/integrations/ruvector/hyperbolic.ts +1948 -0
  55. package/src/integrations/ruvector/index.ts +394 -0
  56. package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
  57. package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
  58. package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
  59. package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
  60. package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
  61. package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
  62. package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
  63. package/src/integrations/ruvector/migrations/index.ts +35 -0
  64. package/src/integrations/ruvector/migrations/migrations.ts +647 -0
  65. package/src/integrations/ruvector/quantization.ts +2036 -0
  66. package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
  67. package/src/integrations/ruvector/self-learning.ts +2376 -0
  68. package/src/integrations/ruvector/streaming.ts +1737 -0
  69. package/src/integrations/ruvector/types.ts +1945 -0
  70. package/src/providers/index.ts +643 -0
  71. package/src/registry/dependency-graph.ts +568 -0
  72. package/src/registry/enhanced-plugin-registry.ts +994 -0
  73. package/src/registry/plugin-registry.ts +604 -0
  74. package/src/sdk/index.ts +563 -0
  75. package/src/security/index.ts +594 -0
  76. package/src/types/index.ts +446 -0
  77. package/src/workers/index.ts +700 -0
  78. package/tmp.json +0 -0
  79. package/tsconfig.json +25 -0
  80. package/vitest.config.ts +23 -0
@@ -0,0 +1,643 @@
1
+ /**
2
+ * LLM Provider Integration Module
3
+ *
4
+ * Provides unified interface for LLM providers in the plugin system.
5
+ * Enables multi-provider support, fallback chains, and cost optimization.
6
+ */
7
+
8
+ import { EventEmitter } from 'events';
9
+ import type {
10
+ LLMProviderDefinition,
11
+ LLMCapability,
12
+ LLMRequest,
13
+ LLMResponse,
14
+ LLMMessage,
15
+ LLMTool,
16
+ LLMToolCall,
17
+ RateLimitConfig,
18
+ CostConfig,
19
+ ILogger,
20
+ IEventBus,
21
+ } from '../types/index.js';
22
+
23
+ // ============================================================================
24
+ // Provider Events
25
+ // ============================================================================
26
+
27
+ export const PROVIDER_EVENTS = {
28
+ REGISTERED: 'provider:registered',
29
+ UNREGISTERED: 'provider:unregistered',
30
+ REQUEST_START: 'provider:request-start',
31
+ REQUEST_COMPLETE: 'provider:request-complete',
32
+ REQUEST_ERROR: 'provider:request-error',
33
+ RATE_LIMITED: 'provider:rate-limited',
34
+ FALLBACK: 'provider:fallback',
35
+ } as const;
36
+
37
+ export type ProviderEvent = typeof PROVIDER_EVENTS[keyof typeof PROVIDER_EVENTS];
38
+
39
+ // ============================================================================
40
+ // Provider Interface
41
+ // ============================================================================
42
+
43
+ export interface ILLMProvider {
44
+ readonly definition: LLMProviderDefinition;
45
+
46
+ complete(request: LLMRequest): Promise<LLMResponse>;
47
+ stream?(request: LLMRequest): AsyncIterable<Partial<LLMResponse>>;
48
+ embed?(texts: string[]): Promise<number[][]>;
49
+
50
+ healthCheck(): Promise<{ healthy: boolean; latencyMs: number }>;
51
+ getRateLimitStatus(): RateLimitStatus;
52
+ getCostEstimate(request: LLMRequest): number;
53
+ }
54
+
55
+ export interface RateLimitStatus {
56
+ requestsRemaining: number;
57
+ tokensRemaining: number;
58
+ resetAt: Date;
59
+ isLimited: boolean;
60
+ }
61
+
62
+ // ============================================================================
63
+ // Provider Registry
64
+ // ============================================================================
65
+
66
+ export interface ProviderRegistryConfig {
67
+ logger?: ILogger;
68
+ eventBus?: IEventBus;
69
+ defaultProvider?: string;
70
+ fallbackChain?: string[];
71
+ costOptimization?: boolean;
72
+ retryConfig?: RetryConfig;
73
+ }
74
+
75
+ export interface RetryConfig {
76
+ maxRetries: number;
77
+ initialDelayMs: number;
78
+ maxDelayMs: number;
79
+ backoffMultiplier: number;
80
+ }
81
+
82
+ export interface ProviderEntry {
83
+ readonly provider: ILLMProvider;
84
+ readonly registeredAt: Date;
85
+ requestCount: number;
86
+ errorCount: number;
87
+ totalTokensUsed: number;
88
+ totalCost: number;
89
+ lastUsed?: Date;
90
+ }
91
+
92
+ export interface ProviderRegistryStats {
93
+ totalProviders: number;
94
+ totalRequests: number;
95
+ totalErrors: number;
96
+ totalTokensUsed: number;
97
+ totalCost: number;
98
+ providerStats: Record<string, {
99
+ requests: number;
100
+ errors: number;
101
+ tokensUsed: number;
102
+ cost: number;
103
+ avgLatency: number;
104
+ }>;
105
+ }
106
+
107
+ /**
108
+ * Central registry for LLM provider management.
109
+ */
110
+ export class ProviderRegistry extends EventEmitter {
111
+ private readonly providers = new Map<string, ProviderEntry>();
112
+ private readonly config: ProviderRegistryConfig;
113
+ private readonly latencyTracking = new Map<string, number[]>();
114
+
115
+ constructor(config?: ProviderRegistryConfig) {
116
+ super();
117
+ this.config = {
118
+ costOptimization: false,
119
+ retryConfig: {
120
+ maxRetries: 3,
121
+ initialDelayMs: 1000,
122
+ maxDelayMs: 30000,
123
+ backoffMultiplier: 2,
124
+ },
125
+ ...config,
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Register a provider.
131
+ */
132
+ register(provider: ILLMProvider): void {
133
+ const name = provider.definition.name;
134
+
135
+ if (this.providers.has(name)) {
136
+ throw new Error(`Provider ${name} already registered`);
137
+ }
138
+
139
+ const entry: ProviderEntry = {
140
+ provider,
141
+ registeredAt: new Date(),
142
+ requestCount: 0,
143
+ errorCount: 0,
144
+ totalTokensUsed: 0,
145
+ totalCost: 0,
146
+ };
147
+
148
+ this.providers.set(name, entry);
149
+ this.latencyTracking.set(name, []);
150
+ this.emit(PROVIDER_EVENTS.REGISTERED, { provider: name });
151
+ }
152
+
153
+ /**
154
+ * Unregister a provider.
155
+ */
156
+ unregister(name: string): boolean {
157
+ const removed = this.providers.delete(name);
158
+ if (removed) {
159
+ this.latencyTracking.delete(name);
160
+ this.emit(PROVIDER_EVENTS.UNREGISTERED, { provider: name });
161
+ }
162
+ return removed;
163
+ }
164
+
165
+ /**
166
+ * Get a provider by name.
167
+ */
168
+ get(name: string): ILLMProvider | undefined {
169
+ return this.providers.get(name)?.provider;
170
+ }
171
+
172
+ /**
173
+ * Get the best available provider based on criteria.
174
+ */
175
+ getBest(options?: {
176
+ capabilities?: LLMCapability[];
177
+ model?: string;
178
+ preferCheaper?: boolean;
179
+ }): ILLMProvider | undefined {
180
+ let candidates = Array.from(this.providers.values());
181
+
182
+ // Filter by capabilities
183
+ if (options?.capabilities) {
184
+ candidates = candidates.filter(e =>
185
+ options.capabilities!.every(cap =>
186
+ e.provider.definition.capabilities.includes(cap)
187
+ )
188
+ );
189
+ }
190
+
191
+ // Filter by model support
192
+ if (options?.model) {
193
+ candidates = candidates.filter(e =>
194
+ e.provider.definition.models.includes(options.model!)
195
+ );
196
+ }
197
+
198
+ // Filter by rate limit availability
199
+ candidates = candidates.filter(e => !e.provider.getRateLimitStatus().isLimited);
200
+
201
+ if (candidates.length === 0) {
202
+ return undefined;
203
+ }
204
+
205
+ // Sort by preference
206
+ if (options?.preferCheaper || this.config.costOptimization) {
207
+ candidates.sort((a, b) => {
208
+ const costA = a.provider.definition.costPerToken?.input ?? 0;
209
+ const costB = b.provider.definition.costPerToken?.input ?? 0;
210
+ return costA - costB;
211
+ });
212
+ } else {
213
+ // Sort by success rate
214
+ candidates.sort((a, b) => {
215
+ const rateA = a.requestCount > 0 ? (a.requestCount - a.errorCount) / a.requestCount : 1;
216
+ const rateB = b.requestCount > 0 ? (b.requestCount - b.errorCount) / b.requestCount : 1;
217
+ return rateB - rateA;
218
+ });
219
+ }
220
+
221
+ return candidates[0]?.provider;
222
+ }
223
+
224
+ /**
225
+ * Execute a request with automatic provider selection and fallback.
226
+ */
227
+ async execute(request: LLMRequest): Promise<LLMResponse> {
228
+ const provider = this.getBest({ model: request.model });
229
+
230
+ if (!provider) {
231
+ throw new Error(`No available provider for model ${request.model}`);
232
+ }
233
+
234
+ return this.executeWithProvider(provider.definition.name, request);
235
+ }
236
+
237
+ /**
238
+ * Execute a request on a specific provider with retry.
239
+ */
240
+ async executeWithProvider(providerName: string, request: LLMRequest): Promise<LLMResponse> {
241
+ const entry = this.providers.get(providerName);
242
+ if (!entry) {
243
+ throw new Error(`Provider ${providerName} not found`);
244
+ }
245
+
246
+ const retryConfig = this.config.retryConfig!;
247
+ let lastError: Error | null = null;
248
+ let delay = retryConfig.initialDelayMs;
249
+
250
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
251
+ if (attempt > 0) {
252
+ await this.delay(delay);
253
+ delay = Math.min(delay * retryConfig.backoffMultiplier, retryConfig.maxDelayMs);
254
+ }
255
+
256
+ try {
257
+ this.emit(PROVIDER_EVENTS.REQUEST_START, {
258
+ provider: providerName,
259
+ model: request.model,
260
+ attempt,
261
+ });
262
+
263
+ const startTime = Date.now();
264
+ const response = await entry.provider.complete(request);
265
+ const latency = Date.now() - startTime;
266
+
267
+ // Update metrics
268
+ entry.requestCount++;
269
+ entry.lastUsed = new Date();
270
+ entry.totalTokensUsed += response.usage.totalTokens;
271
+ entry.totalCost += entry.provider.getCostEstimate(request);
272
+
273
+ // Track latency
274
+ const latencies = this.latencyTracking.get(providerName)!;
275
+ latencies.push(latency);
276
+ if (latencies.length > 100) latencies.shift();
277
+
278
+ this.emit(PROVIDER_EVENTS.REQUEST_COMPLETE, {
279
+ provider: providerName,
280
+ model: request.model,
281
+ latencyMs: latency,
282
+ tokensUsed: response.usage.totalTokens,
283
+ });
284
+
285
+ return response;
286
+ } catch (error) {
287
+ lastError = error instanceof Error ? error : new Error(String(error));
288
+ entry.errorCount++;
289
+
290
+ this.emit(PROVIDER_EVENTS.REQUEST_ERROR, {
291
+ provider: providerName,
292
+ model: request.model,
293
+ error: lastError.message,
294
+ attempt,
295
+ });
296
+
297
+ // Check if we should try fallback
298
+ if (attempt === retryConfig.maxRetries && this.config.fallbackChain) {
299
+ const fallbackResult = await this.tryFallback(request, providerName);
300
+ if (fallbackResult) {
301
+ return fallbackResult;
302
+ }
303
+ }
304
+ }
305
+ }
306
+
307
+ throw lastError ?? new Error('Unknown error during provider execution');
308
+ }
309
+
310
+ private async tryFallback(
311
+ request: LLMRequest,
312
+ failedProvider: string
313
+ ): Promise<LLMResponse | null> {
314
+ const fallbackChain = this.config.fallbackChain ?? [];
315
+
316
+ for (const fallbackName of fallbackChain) {
317
+ if (fallbackName === failedProvider) continue;
318
+
319
+ const fallbackEntry = this.providers.get(fallbackName);
320
+ if (!fallbackEntry) continue;
321
+
322
+ // Check if fallback supports the model
323
+ if (!fallbackEntry.provider.definition.models.includes(request.model)) {
324
+ continue;
325
+ }
326
+
327
+ // Check rate limit
328
+ if (fallbackEntry.provider.getRateLimitStatus().isLimited) {
329
+ continue;
330
+ }
331
+
332
+ try {
333
+ this.emit(PROVIDER_EVENTS.FALLBACK, {
334
+ from: failedProvider,
335
+ to: fallbackName,
336
+ });
337
+
338
+ return await this.executeWithProvider(fallbackName, request);
339
+ } catch {
340
+ // Try next fallback
341
+ continue;
342
+ }
343
+ }
344
+
345
+ return null;
346
+ }
347
+
348
+ private delay(ms: number): Promise<void> {
349
+ return new Promise(resolve => setTimeout(resolve, ms));
350
+ }
351
+
352
+ /**
353
+ * List all registered providers.
354
+ */
355
+ list(): LLMProviderDefinition[] {
356
+ return Array.from(this.providers.values()).map(e => e.provider.definition);
357
+ }
358
+
359
+ /**
360
+ * Get provider statistics.
361
+ */
362
+ getStats(): ProviderRegistryStats {
363
+ let totalRequests = 0;
364
+ let totalErrors = 0;
365
+ let totalTokensUsed = 0;
366
+ let totalCost = 0;
367
+ const providerStats: ProviderRegistryStats['providerStats'] = {};
368
+
369
+ for (const [name, entry] of this.providers) {
370
+ totalRequests += entry.requestCount;
371
+ totalErrors += entry.errorCount;
372
+ totalTokensUsed += entry.totalTokensUsed;
373
+ totalCost += entry.totalCost;
374
+
375
+ const latencies = this.latencyTracking.get(name) ?? [];
376
+ const avgLatency = latencies.length > 0
377
+ ? latencies.reduce((a, b) => a + b, 0) / latencies.length
378
+ : 0;
379
+
380
+ providerStats[name] = {
381
+ requests: entry.requestCount,
382
+ errors: entry.errorCount,
383
+ tokensUsed: entry.totalTokensUsed,
384
+ cost: entry.totalCost,
385
+ avgLatency,
386
+ };
387
+ }
388
+
389
+ return {
390
+ totalProviders: this.providers.size,
391
+ totalRequests,
392
+ totalErrors,
393
+ totalTokensUsed,
394
+ totalCost,
395
+ providerStats,
396
+ };
397
+ }
398
+
399
+ /**
400
+ * Health check all providers.
401
+ */
402
+ async healthCheck(): Promise<Map<string, { healthy: boolean; latencyMs: number }>> {
403
+ const results = new Map<string, { healthy: boolean; latencyMs: number }>();
404
+
405
+ for (const [name, entry] of this.providers) {
406
+ try {
407
+ results.set(name, await entry.provider.healthCheck());
408
+ } catch {
409
+ results.set(name, { healthy: false, latencyMs: -1 });
410
+ }
411
+ }
412
+
413
+ return results;
414
+ }
415
+ }
416
+
417
+ // ============================================================================
418
+ // Base Provider Implementation
419
+ // ============================================================================
420
+
421
+ /**
422
+ * Abstract base class for LLM providers.
423
+ */
424
+ export abstract class BaseLLMProvider implements ILLMProvider {
425
+ readonly definition: LLMProviderDefinition;
426
+ protected rateLimitState: {
427
+ requestsInWindow: number;
428
+ tokensInWindow: number;
429
+ windowStart: Date;
430
+ };
431
+
432
+ constructor(definition: LLMProviderDefinition) {
433
+ this.definition = definition;
434
+ this.rateLimitState = {
435
+ requestsInWindow: 0,
436
+ tokensInWindow: 0,
437
+ windowStart: new Date(),
438
+ };
439
+ }
440
+
441
+ abstract complete(request: LLMRequest): Promise<LLMResponse>;
442
+
443
+ stream?(request: LLMRequest): AsyncIterable<Partial<LLMResponse>>;
444
+ embed?(texts: string[]): Promise<number[][]>;
445
+
446
+ async healthCheck(): Promise<{ healthy: boolean; latencyMs: number }> {
447
+ const start = Date.now();
448
+ try {
449
+ // Simple ping test
450
+ await this.complete({
451
+ model: this.definition.models[0],
452
+ messages: [{ role: 'user', content: 'ping' }],
453
+ maxTokens: 5,
454
+ });
455
+ return { healthy: true, latencyMs: Date.now() - start };
456
+ } catch {
457
+ return { healthy: false, latencyMs: Date.now() - start };
458
+ }
459
+ }
460
+
461
+ getRateLimitStatus(): RateLimitStatus {
462
+ const config = this.definition.rateLimit;
463
+ if (!config) {
464
+ return {
465
+ requestsRemaining: Infinity,
466
+ tokensRemaining: Infinity,
467
+ resetAt: new Date(Date.now() + 60000),
468
+ isLimited: false,
469
+ };
470
+ }
471
+
472
+ // Check if window has reset
473
+ const windowMs = 60000; // 1 minute window
474
+ const now = new Date();
475
+ if (now.getTime() - this.rateLimitState.windowStart.getTime() > windowMs) {
476
+ this.rateLimitState = {
477
+ requestsInWindow: 0,
478
+ tokensInWindow: 0,
479
+ windowStart: now,
480
+ };
481
+ }
482
+
483
+ const requestsRemaining = config.requestsPerMinute - this.rateLimitState.requestsInWindow;
484
+ const tokensRemaining = config.tokensPerMinute - this.rateLimitState.tokensInWindow;
485
+ const resetAt = new Date(this.rateLimitState.windowStart.getTime() + windowMs);
486
+
487
+ return {
488
+ requestsRemaining,
489
+ tokensRemaining,
490
+ resetAt,
491
+ isLimited: requestsRemaining <= 0 || tokensRemaining <= 0,
492
+ };
493
+ }
494
+
495
+ getCostEstimate(request: LLMRequest): number {
496
+ const costConfig = this.definition.costPerToken;
497
+ if (!costConfig) return 0;
498
+
499
+ // Rough token estimate: ~4 chars per token
500
+ const inputTokens = request.messages.reduce(
501
+ (sum, m) => sum + Math.ceil(m.content.length / 4),
502
+ 0
503
+ );
504
+ const outputTokens = request.maxTokens ?? 1000;
505
+
506
+ return (inputTokens * costConfig.input) + (outputTokens * costConfig.output);
507
+ }
508
+
509
+ protected updateRateLimits(tokensUsed: number): void {
510
+ this.rateLimitState.requestsInWindow++;
511
+ this.rateLimitState.tokensInWindow += tokensUsed;
512
+ }
513
+ }
514
+
515
+ // ============================================================================
516
+ // Provider Factory
517
+ // ============================================================================
518
+
519
+ /**
520
+ * Factory for creating provider definitions.
521
+ */
522
+ export class ProviderFactory {
523
+ /**
524
+ * Create an Anthropic Claude provider definition.
525
+ */
526
+ static createClaude(options?: {
527
+ displayName?: string;
528
+ models?: string[];
529
+ rateLimit?: RateLimitConfig;
530
+ costPerToken?: CostConfig;
531
+ }): LLMProviderDefinition {
532
+ return {
533
+ name: 'anthropic',
534
+ displayName: options?.displayName ?? 'Anthropic Claude',
535
+ models: options?.models ?? [
536
+ 'claude-opus-4-5-20251101',
537
+ 'claude-sonnet-4-20250514',
538
+ 'claude-3-5-haiku-20241022',
539
+ ],
540
+ capabilities: [
541
+ 'completion',
542
+ 'chat',
543
+ 'streaming',
544
+ 'function-calling',
545
+ 'vision',
546
+ 'code-generation',
547
+ ],
548
+ rateLimit: options?.rateLimit ?? {
549
+ requestsPerMinute: 50,
550
+ tokensPerMinute: 100000,
551
+ },
552
+ costPerToken: options?.costPerToken ?? {
553
+ input: 0.000003,
554
+ output: 0.000015,
555
+ currency: 'USD',
556
+ },
557
+ };
558
+ }
559
+
560
+ /**
561
+ * Create an OpenAI provider definition.
562
+ */
563
+ static createOpenAI(options?: {
564
+ displayName?: string;
565
+ models?: string[];
566
+ rateLimit?: RateLimitConfig;
567
+ costPerToken?: CostConfig;
568
+ }): LLMProviderDefinition {
569
+ return {
570
+ name: 'openai',
571
+ displayName: options?.displayName ?? 'OpenAI',
572
+ models: options?.models ?? [
573
+ 'gpt-4o',
574
+ 'gpt-4o-mini',
575
+ 'gpt-4-turbo',
576
+ 'gpt-3.5-turbo',
577
+ ],
578
+ capabilities: [
579
+ 'completion',
580
+ 'chat',
581
+ 'streaming',
582
+ 'function-calling',
583
+ 'vision',
584
+ 'embeddings',
585
+ 'code-generation',
586
+ ],
587
+ rateLimit: options?.rateLimit ?? {
588
+ requestsPerMinute: 60,
589
+ tokensPerMinute: 150000,
590
+ },
591
+ costPerToken: options?.costPerToken ?? {
592
+ input: 0.00001,
593
+ output: 0.00003,
594
+ currency: 'USD',
595
+ },
596
+ };
597
+ }
598
+
599
+ /**
600
+ * Create a local/self-hosted provider definition.
601
+ */
602
+ static createLocal(options: {
603
+ name: string;
604
+ displayName: string;
605
+ models: string[];
606
+ capabilities: LLMCapability[];
607
+ endpoint?: string;
608
+ }): LLMProviderDefinition {
609
+ return {
610
+ name: options.name,
611
+ displayName: options.displayName,
612
+ models: options.models,
613
+ capabilities: options.capabilities,
614
+ // No rate limits for local
615
+ rateLimit: undefined,
616
+ // No cost for local
617
+ costPerToken: undefined,
618
+ };
619
+ }
620
+
621
+ /**
622
+ * Create a custom provider definition.
623
+ */
624
+ static createCustom(definition: LLMProviderDefinition): LLMProviderDefinition {
625
+ return { ...definition };
626
+ }
627
+ }
628
+
629
+ // ============================================================================
630
+ // Exports
631
+ // ============================================================================
632
+
633
+ export type {
634
+ LLMProviderDefinition,
635
+ LLMCapability,
636
+ LLMRequest,
637
+ LLMResponse,
638
+ LLMMessage,
639
+ LLMTool,
640
+ LLMToolCall,
641
+ RateLimitConfig,
642
+ CostConfig,
643
+ };