@x12i/ai-providers-router 4.6.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 (58) hide show
  1. package/.metadata/anthropic.response-map.json +1 -0
  2. package/.metadata/google.response-map.json +1 -0
  3. package/.metadata/groq.response-map.json +1 -0
  4. package/.metadata/llm-request-config-registry.json +111 -0
  5. package/.metadata/llm-response-config-registry.json +1 -0
  6. package/.metadata/model-aliases.json +1 -0
  7. package/.metadata/model-normalization.json +1 -0
  8. package/.metadata/moonshot.response-map.json +1 -0
  9. package/.metadata/openai.response-map.json +1 -0
  10. package/.metadata/openrouter_catalog_with_vendor_mapping.json +15781 -0
  11. package/.metadata/reasoning-support.json +159 -0
  12. package/.metadata/xai.response-map.json +1 -0
  13. package/README.md +480 -0
  14. package/dist/adapters/grok/GrokAdapter.d.ts +50 -0
  15. package/dist/adapters/grok/GrokAdapter.js +342 -0
  16. package/dist/adapters/openai/OpenAIAdapter.d.ts +50 -0
  17. package/dist/adapters/openai/OpenAIAdapter.js +401 -0
  18. package/dist/adapters/openrouter/OpenRouterAdapter.d.ts +87 -0
  19. package/dist/adapters/openrouter/OpenRouterAdapter.js +1449 -0
  20. package/dist/adapters/openrouter/reasoning-capabilities.d.ts +26 -0
  21. package/dist/adapters/openrouter/reasoning-capabilities.js +79 -0
  22. package/dist/discovery.d.ts +6 -0
  23. package/dist/discovery.js +114 -0
  24. package/dist/errors.d.ts +27 -0
  25. package/dist/errors.js +33 -0
  26. package/dist/factory.d.ts +15 -0
  27. package/dist/factory.js +206 -0
  28. package/dist/gateway.d.ts +22 -0
  29. package/dist/gateway.js +154 -0
  30. package/dist/index.d.ts +9 -0
  31. package/dist/index.js +42 -0
  32. package/dist/interceptors.d.ts +10 -0
  33. package/dist/interceptors.js +1 -0
  34. package/dist/logger.d.ts +70 -0
  35. package/dist/logger.js +222 -0
  36. package/dist/openrouter-catalog.d.ts +119 -0
  37. package/dist/openrouter-catalog.js +222 -0
  38. package/dist/providers/OpenRouterProvider.d.ts +16 -0
  39. package/dist/providers/OpenRouterProvider.js +171 -0
  40. package/dist/registry/AdapterRegistry.d.ts +86 -0
  41. package/dist/registry/AdapterRegistry.js +36 -0
  42. package/dist/registry/ProviderRegistry.d.ts +24 -0
  43. package/dist/registry/ProviderRegistry.js +46 -0
  44. package/dist/router/Router.d.ts +33 -0
  45. package/dist/router/Router.js +258 -0
  46. package/dist/router/RouterTypes.d.ts +138 -0
  47. package/dist/router/RouterTypes.js +5 -0
  48. package/dist/router/RouterWrapper.d.ts +83 -0
  49. package/dist/router/RouterWrapper.js +744 -0
  50. package/dist/router.d.ts +13 -0
  51. package/dist/router.js +8 -0
  52. package/dist/types.d.ts +33 -0
  53. package/dist/types.js +1 -0
  54. package/dist/utils/esm-compat.d.ts +9 -0
  55. package/dist/utils/esm-compat.js +13 -0
  56. package/dist/utils/ids.d.ts +4 -0
  57. package/dist/utils/ids.js +6 -0
  58. package/package.json +66 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Reasoning capabilities loader from JSON registry
3
+ * Provides cross-vendor reasoning support detection
4
+ */
5
+ type ReasoningMode = 'none' | 'effort' | 'max_tokens' | 'both';
6
+ export interface ReasoningVisibilitySupport {
7
+ summary: boolean;
8
+ text: boolean;
9
+ encrypted: boolean;
10
+ }
11
+ export interface ReasoningCapabilities {
12
+ supportsReasoningDetails: boolean;
13
+ mode: ReasoningMode;
14
+ visibility: ReasoningVisibilitySupport;
15
+ supportedEfforts?: string[];
16
+ vendorId?: string;
17
+ }
18
+ /**
19
+ * Load reasoning capabilities from JSON registry based on model ID
20
+ */
21
+ export declare function getReasoningCapabilitiesFromRegistry(modelId: string): ReasoningCapabilities | null;
22
+ /**
23
+ * Check if model has reasoning parameter in catalog
24
+ */
25
+ export declare function hasReasoningParamInCatalog(model: any): boolean;
26
+ export {};
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Reasoning capabilities loader from JSON registry
3
+ * Provides cross-vendor reasoning support detection
4
+ */
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { getDirname } from '../../utils/esm-compat.js';
8
+ // Get __dirname equivalent for ESM
9
+ const __dirname = getDirname(import.meta.url);
10
+ // Load reasoning support registry from JSON file
11
+ // Using same pattern as openrouter-catalog.ts
12
+ let reasoningSupportRegistry;
13
+ try {
14
+ // __dirname in compiled JS will be dist/adapters/openrouter, so go up to root
15
+ // In TS source, __dirname will be src/adapters/openrouter
16
+ const registryPath = path.join(__dirname, '..', '..', '..', '.metadata', 'reasoning-support.json');
17
+ const registryContent = fs.readFileSync(registryPath, 'utf-8');
18
+ reasoningSupportRegistry = JSON.parse(registryContent);
19
+ }
20
+ catch (error) {
21
+ console.warn('[reasoning-capabilities] Failed to load reasoning-support.json, using empty registry:', error);
22
+ reasoningSupportRegistry = { vendors: [] };
23
+ }
24
+ /**
25
+ * Load reasoning capabilities from JSON registry based on model ID
26
+ */
27
+ export function getReasoningCapabilitiesFromRegistry(modelId) {
28
+ const canonicalSlug = modelId.toLowerCase();
29
+ // Iterate through vendors in registry
30
+ for (const vendor of reasoningSupportRegistry.vendors) {
31
+ if (!vendor.supportsReasoningDetails) {
32
+ continue;
33
+ }
34
+ // Check each model match rule
35
+ for (const rule of vendor.modelMatchRules) {
36
+ let matches = false;
37
+ if (rule.matchType === 'prefix') {
38
+ matches = canonicalSlug.startsWith(rule.pattern.toLowerCase());
39
+ }
40
+ else if (rule.matchType === 'regex') {
41
+ const regex = new RegExp(rule.pattern, 'i');
42
+ matches = regex.test(canonicalSlug);
43
+ }
44
+ else if (rule.matchType === 'exact') {
45
+ matches = canonicalSlug === rule.pattern.toLowerCase();
46
+ }
47
+ if (matches) {
48
+ // Determine mode from requestModes
49
+ let mode = 'none';
50
+ if (vendor.requestModes.includes('effort') && vendor.requestModes.includes('max_tokens')) {
51
+ mode = 'both';
52
+ }
53
+ else if (vendor.requestModes.includes('effort')) {
54
+ mode = 'effort';
55
+ }
56
+ else if (vendor.requestModes.includes('max_tokens')) {
57
+ mode = 'max_tokens';
58
+ }
59
+ return {
60
+ supportsReasoningDetails: true,
61
+ mode,
62
+ visibility: vendor.visibilitySupport,
63
+ supportedEfforts: mode === 'effort' || mode === 'both'
64
+ ? ['low', 'medium', 'high'] // xhigh normalized to high
65
+ : undefined,
66
+ vendorId: vendor.vendorId,
67
+ };
68
+ }
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ /**
74
+ * Check if model has reasoning parameter in catalog
75
+ */
76
+ export function hasReasoningParamInCatalog(model) {
77
+ return model?.capabilities?.supportedParameters?.includes('reasoning') ||
78
+ model?.capabilities?.supportedParameters?.includes('include_reasoning');
79
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Auto-discover installed provider packages
3
+ * This is a simplified implementation - in practice, you'd scan node_modules
4
+ * for packages matching the pattern @x12i/llm-provider-*
5
+ */
6
+ export {};
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Auto-discover installed provider packages
3
+ * This is a simplified implementation - in practice, you'd scan node_modules
4
+ * for packages matching the pattern @x12i/llm-provider-*
5
+ */
6
+ /*
7
+ async function discoverProviders(
8
+ providerConfigs?: Record<string, any>
9
+ ): Promise<any[]> {
10
+ const providers: any[] = [];
11
+
12
+ // Common provider package patterns
13
+ const providerPackages = [
14
+ '@x12i/ai-provider-openai',
15
+ '@x12i/ai-provider-grok',
16
+ ];
17
+
18
+
19
+ // Also check for @x12i/x-models which may export a provider
20
+ try {
21
+ const xModelsModule = await import('@x12i/x-models').catch(() => null);
22
+ if (xModelsModule) {
23
+ // Look for provider class - check common export patterns
24
+ const XModelsProvider = (xModelsModule as any).XModelsAdapterProvider ||
25
+ (xModelsModule as any).default ||
26
+ (xModelsModule as any).Provider ||
27
+ (xModelsModule as any).LLMProvider;
28
+ if (XModelsProvider && typeof XModelsProvider === 'function') {
29
+ const config = providerConfigs?.['x-models'] || {};
30
+ try {
31
+ const providerInstance = new XModelsProvider(config);
32
+ if (typeof providerInstance.invoke === 'function') {
33
+ providers.push(providerInstance);
34
+ }
35
+ } catch (error) {
36
+ // Provider instantiation failed, skip it
37
+ }
38
+ }
39
+ }
40
+ } catch (error) {
41
+ // Package not available, skip it
42
+ }
43
+
44
+ for (const packageName of providerPackages) {
45
+ try {
46
+ // Try to dynamically import the provider
47
+ const providerModule = await import(packageName).catch(() => null);
48
+ if (!providerModule) continue;
49
+
50
+ // Look for default export or named exports
51
+ const exported =
52
+ providerModule.default || providerModule.provider || providerModule[getProviderClassName(packageName)];
53
+
54
+ if (!exported) continue;
55
+
56
+ const providerName = extractProviderName(packageName);
57
+ const config = providerConfigs?.[providerName] || {};
58
+ let providerInstance: any;
59
+
60
+ if (typeof exported === 'function') {
61
+ // Handle class constructor
62
+ try {
63
+ providerInstance = new (exported as any)(config);
64
+ } catch (e) {
65
+ // If 'new' fails, try calling as a factory
66
+ try {
67
+ providerInstance = (exported as any)(config);
68
+ } catch (e2) {
69
+ // Both failed
70
+ }
71
+ }
72
+ } else if (typeof exported === 'object' && exported !== null) {
73
+ // Handle direct object export (ProviderModule) or factory-like object
74
+ if (typeof (exported as any).initializeClient === 'function') {
75
+ providerInstance = (exported as any).initializeClient(config);
76
+ } else if (exported.name && exported.execute) {
77
+ providerInstance = exported;
78
+ }
79
+ }
80
+
81
+ if (providerInstance) {
82
+ // Check for both invoke (LLMProviderInterface) and aiCall (AIProviderInterface)
83
+ if (typeof providerInstance.invoke === 'function' || typeof providerInstance.aiCall === 'function') {
84
+ providers.push(providerInstance);
85
+ }
86
+ } else {
87
+ console.warn(`Failed to instantiate provider ${packageName}: No valid constructor or factory found`);
88
+ }
89
+ } catch (error) {
90
+ // Package not installed or not available, skip it
91
+ continue;
92
+ }
93
+ }
94
+
95
+ return providers;
96
+ }v
97
+ */
98
+ function getProviderClassName(packageName) {
99
+ const parts = packageName.split('/');
100
+ const name = parts[parts.length - 1];
101
+ // Handle both ai-provider-* and llm-provider-* patterns
102
+ const cleanName = name.replace('ai-provider-', '').replace('llm-provider-', '');
103
+ const className = cleanName
104
+ .split('-')
105
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
106
+ .join('') + 'Provider';
107
+ return className;
108
+ }
109
+ function extractProviderName(packageName) {
110
+ const parts = packageName.split('/');
111
+ const name = parts[parts.length - 1];
112
+ return name.replace('ai-provider-', '').replace('llm-provider-', '');
113
+ }
114
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { ProviderId } from './types.js';
2
+ /**
3
+ * Error thrown when a requested provider is not registered
4
+ */
5
+ export declare class ProviderNotFoundError extends Error {
6
+ constructor(providerName: ProviderId | string);
7
+ }
8
+ /**
9
+ * Error thrown when all providers in the fallback chain have failed
10
+ */
11
+ export declare class FallbackExhaustedError extends Error {
12
+ attempts: Array<{
13
+ provider: ProviderId;
14
+ error: Error;
15
+ }>;
16
+ constructor(attempts: Array<{
17
+ provider: ProviderId;
18
+ error: Error;
19
+ }>);
20
+ }
21
+ /**
22
+ * Error thrown when a provider package is not installed
23
+ */
24
+ export declare class ProviderNotInstalledError extends Error {
25
+ packageName: string;
26
+ constructor(providerName: ProviderId | string, packageName: string);
27
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Error thrown when a requested provider is not registered
3
+ */
4
+ export class ProviderNotFoundError extends Error {
5
+ constructor(providerName) {
6
+ super(`Provider '${providerName}' not registered`);
7
+ this.name = 'ProviderNotFoundError';
8
+ Object.setPrototypeOf(this, ProviderNotFoundError.prototype);
9
+ }
10
+ }
11
+ /**
12
+ * Error thrown when all providers in the fallback chain have failed
13
+ */
14
+ export class FallbackExhaustedError extends Error {
15
+ constructor(attempts) {
16
+ super('All providers in fallback chain failed');
17
+ this.attempts = attempts;
18
+ this.name = 'FallbackExhaustedError';
19
+ Object.setPrototypeOf(this, FallbackExhaustedError.prototype);
20
+ }
21
+ }
22
+ /**
23
+ * Error thrown when a provider package is not installed
24
+ */
25
+ export class ProviderNotInstalledError extends Error {
26
+ constructor(providerName, packageName) {
27
+ super(`Provider '${providerName}' is not installed. ` +
28
+ `Install it with: npm install ${packageName} or yarn add ${packageName}`);
29
+ this.packageName = packageName;
30
+ this.name = 'ProviderNotInstalledError';
31
+ Object.setPrototypeOf(this, ProviderNotInstalledError.prototype);
32
+ }
33
+ }
@@ -0,0 +1,15 @@
1
+ import { LLMProviderRouter } from './router/RouterWrapper.js';
2
+ import type { RouterConfig } from './router/RouterTypes.js';
3
+ export interface CreateRouterConfig extends RouterConfig {
4
+ providerConfigs?: Record<string, any>;
5
+ }
6
+ /**
7
+ * Factory function to create a router with automatic provider discovery and configuration
8
+ * ERC-compliant: Supports zero-config initialization from environment variables
9
+ */
10
+ export declare function createRouter(config?: CreateRouterConfig): Promise<LLMProviderRouter>;
11
+ /**
12
+ * Create router from configuration file (legacy support)
13
+ * Note: For ERC compliance, prefer createRouter() with environment variables
14
+ */
15
+ export declare function createRouterFromConfig(configPath: string): Promise<LLMProviderRouter>;
@@ -0,0 +1,206 @@
1
+ import { LLMProviderRouter } from './router/RouterWrapper.js';
2
+ import dns from 'node:dns';
3
+ import dotenv from 'dotenv';
4
+ // Fix IPv6-first DNS resolution issue on Windows (forces IPv4-first to avoid connect timeouts)
5
+ // This prevents undici from trying IPv6 first on networks that silently drop IPv6 traffic
6
+ // Must be set before any network calls are made
7
+ dns.setDefaultResultOrder('ipv4first');
8
+ // Set undici global dispatcher connectTimeout to prevent hard 10s connect timeout
9
+ // This must be done before any provider initializes to ensure all fetch calls use the correct timeout
10
+ // Dynamic import for optional dependency (undici might not be available)
11
+ (async () => {
12
+ try {
13
+ const { Agent, setGlobalDispatcher } = await import('undici');
14
+ // Set a reasonable default connect timeout (60s) - providers can override via their config
15
+ // This prevents undici's hard-coded 10s connect timeout from causing premature failures
16
+ const defaultConnectTimeout = 60000; // 60 seconds
17
+ setGlobalDispatcher(new Agent({
18
+ connectTimeout: defaultConnectTimeout,
19
+ }));
20
+ }
21
+ catch (e) {
22
+ // undici not available or already set - continue without it
23
+ // This is a best-effort fix; providers should also set their own dispatchers
24
+ }
25
+ })();
26
+ // Load environment variables from .env file if available
27
+ // This ensures nx-config2 can resolve ENV. placeholders
28
+ // dotenv.config() is idempotent and won't overwrite existing process.env values
29
+ dotenv.config();
30
+ /**
31
+ * Resolve ENV. placeholders to actual environment variable values
32
+ * Replaces nx-config2 functionality to avoid ESM/CommonJS compatibility issues
33
+ */
34
+ function resolveEnvPlaceholders(config) {
35
+ if (typeof config === 'string') {
36
+ // Handle ENV.VAR_NAME||default pattern
37
+ if (config.startsWith('ENV.')) {
38
+ const match = config.match(/^ENV\.([^|]+)(?:\|\|(.+))?$/);
39
+ if (match) {
40
+ const envVar = match[1];
41
+ const defaultValue = match[2] !== undefined ? match[2] : undefined;
42
+ const value = process.env[envVar];
43
+ return value !== undefined ? value : (defaultValue !== undefined ? defaultValue : config);
44
+ }
45
+ }
46
+ return config;
47
+ }
48
+ if (Array.isArray(config)) {
49
+ return config.map(item => resolveEnvPlaceholders(item));
50
+ }
51
+ if (config && typeof config === 'object') {
52
+ const resolved = {};
53
+ for (const [key, value] of Object.entries(config)) {
54
+ resolved[key] = resolveEnvPlaceholders(value);
55
+ }
56
+ return resolved;
57
+ }
58
+ return config;
59
+ }
60
+ /**
61
+ * Legacy provider inference function (fallback when catalog is unavailable)
62
+ */
63
+ function inferProviderFromModelLegacy(model) {
64
+ if (model.startsWith('gpt-') || model.startsWith('o1-') || model.startsWith('openai/')) {
65
+ return 'openai';
66
+ }
67
+ else if (model.startsWith('claude-') || model.startsWith('anthropic/')) {
68
+ return 'anthropic';
69
+ }
70
+ else if (model.startsWith('grok-') || model.startsWith('xai/')) {
71
+ return 'grok';
72
+ }
73
+ else if (model.startsWith('gemini-') || model.startsWith('google/')) {
74
+ return 'google';
75
+ }
76
+ else if (model.startsWith('llama-') || model.startsWith('meta-llama/')) {
77
+ return 'meta';
78
+ }
79
+ return undefined;
80
+ }
81
+ /**
82
+ * Factory function to create a router with automatic provider discovery and configuration
83
+ * ERC-compliant: Supports zero-config initialization from environment variables
84
+ */
85
+ export async function createRouter(config) {
86
+ // ERC Configuration: Define router and provider requirements
87
+ // Use our own resolver instead of nx-config2 to avoid ESM/CommonJS compatibility issues
88
+ const ercConfig = {
89
+ // Router-specific configuration
90
+ router: {
91
+ logLevel: 'ENV.AI_PROVIDER_ROUTER_LOG_LEVEL||info',
92
+ verbose: 'ENV.AI_PROVIDER_ROUTER_VERBOSE||false',
93
+ timeoutMs: 'ENV.AI_PROVIDER_ROUTER_TIMEOUT_MS||60000',
94
+ },
95
+ // Provider SDK client configurations (auto-detected from environment)
96
+ providers: {
97
+ openai: {
98
+ apiKey: 'ENV.OPENAI_API_KEY',
99
+ baseURL: 'ENV.OPENAI_API_BASE',
100
+ organization: 'ENV.OPENAI_ORGANIZATION',
101
+ },
102
+ xai: {
103
+ apiKey: 'ENV.GROK_API_KEY',
104
+ baseURL: 'ENV.XAI_API_BASE',
105
+ },
106
+ groq: {
107
+ apiKey: 'ENV.GROQ_API_KEY',
108
+ },
109
+ anthropic: {
110
+ apiKey: 'ENV.ANTHROPIC_API_KEY',
111
+ baseURL: 'ENV.ANTHROPIC_API_BASE',
112
+ },
113
+ google: {
114
+ apiKey: 'ENV.GOOGLE_API_KEY',
115
+ },
116
+ openrouter: {
117
+ apiKey: 'ENV.OPEN_ROUTER_KEY',
118
+ httpReferer: 'ENV.OPEN_ROUTER_HTTP_REFERER',
119
+ xTitle: 'ENV.OPEN_ROUTER_X_TITLE',
120
+ useOpenRouter: 'ENV.USE_OPENROUTER',
121
+ },
122
+ },
123
+ };
124
+ // Resolve ENV. placeholders
125
+ const ercResult = {
126
+ config: resolveEnvPlaceholders(ercConfig)
127
+ };
128
+ // Use explicit config if provided (Advanced Mode), otherwise use ERC auto-discovered config (Zero-Config Mode)
129
+ const finalConfig = Object.keys(config || {}).length > 0 ? config : {
130
+ logLevel: ercResult.config.router.logLevel,
131
+ verbose: ercResult.config.router.verbose === 'true' || ercResult.config.router.verbose === true,
132
+ timeoutMs: ercResult.config.router.timeoutMs ? parseInt(String(ercResult.config.router.timeoutMs), 10) : undefined,
133
+ defaultTimeoutMs: ercResult.config.router.timeoutMs ? parseInt(String(ercResult.config.router.timeoutMs), 10) : undefined,
134
+ };
135
+ const router = new LLMProviderRouter(finalConfig);
136
+ // Configure providers from ERC auto-detected config OR explicit config
137
+ const providerConfigs = config?.providerConfigs || ercResult.config.providers;
138
+ // Check if OpenRouter mode should be enabled
139
+ // Default: true if OPEN_ROUTER_KEY is present, else false
140
+ // Can be explicitly disabled with USE_OPENROUTER=false
141
+ const openRouterKey = providerConfigs.openrouter?.apiKey;
142
+ const useOpenRouterEnv = providerConfigs.openrouter?.useOpenRouter;
143
+ // Check if API key is valid (not placeholder, not empty)
144
+ const hasValidKey = openRouterKey &&
145
+ openRouterKey !== 'ENV.OPEN_ROUTER_KEY' &&
146
+ typeof openRouterKey === 'string' &&
147
+ openRouterKey.trim() !== '';
148
+ // Determine if OpenRouter should be enabled
149
+ // Default to true if key is present, unless explicitly disabled
150
+ let useOpenRouter = false;
151
+ if (hasValidKey) {
152
+ if (useOpenRouterEnv === undefined || useOpenRouterEnv === '' || useOpenRouterEnv === 'true' || useOpenRouterEnv === true) {
153
+ useOpenRouter = true;
154
+ }
155
+ else if (useOpenRouterEnv === 'false' || useOpenRouterEnv === false) {
156
+ useOpenRouter = false;
157
+ }
158
+ else {
159
+ // Default to true if key is present
160
+ useOpenRouter = true;
161
+ }
162
+ }
163
+ // NOTE: We don't need to manually register providers here anymore if they are
164
+ // in environment variables, as LLMProviderRouter will auto-register them
165
+ // on first invoke/stream/createBatch call.
166
+ // We only register them here if they were provided in the explicit config.
167
+ if (config?.providerConfigs) {
168
+ // Manual registration from explicit config
169
+ for (const [name, pConfig] of Object.entries(config.providerConfigs)) {
170
+ if (pConfig && pConfig.apiKey && !pConfig.apiKey.startsWith('ENV.')) {
171
+ router.configureProvider(name, pConfig);
172
+ try {
173
+ if (name === 'openai') {
174
+ const mod = await import('@x12i/ai-provider-openai');
175
+ router.registerProvider(mod, 'initializeClient');
176
+ }
177
+ else if (name === 'grok' || name === 'xai') {
178
+ const mod = await import('@x12i/ai-provider-grok');
179
+ router.registerProvider(mod);
180
+ }
181
+ }
182
+ catch (e) {
183
+ // Skip if provider package not installed
184
+ }
185
+ }
186
+ }
187
+ }
188
+ return router;
189
+ }
190
+ /**
191
+ * Create router from configuration file (legacy support)
192
+ * Note: For ERC compliance, prefer createRouter() with environment variables
193
+ */
194
+ export async function createRouterFromConfig(configPath) {
195
+ // Load config file
196
+ const fs = await import('fs/promises');
197
+ const configContent = await fs.readFile(configPath, 'utf-8');
198
+ const fileConfig = JSON.parse(configContent);
199
+ // Convert file config to router config format
200
+ const routerConfig = {
201
+ providerConfigs: fileConfig.providers,
202
+ logLevel: fileConfig.logLevel,
203
+ verbose: fileConfig.verbose,
204
+ };
205
+ return createRouter(routerConfig);
206
+ }
@@ -0,0 +1,22 @@
1
+ import { LLMProviderRouter } from './router/RouterWrapper.js';
2
+ import type { AIResponse } from './router/RouterTypes.js';
3
+ export interface EnhancedLLMResponse extends AIResponse {
4
+ content?: {
5
+ providerMetadata?: {
6
+ provider?: string;
7
+ model?: string;
8
+ [key: string]: any;
9
+ };
10
+ [key: string]: any;
11
+ };
12
+ metadata?: any;
13
+ }
14
+ export declare class AIGateway {
15
+ private router;
16
+ constructor(router?: LLMProviderRouter);
17
+ invoke(request: any): Promise<EnhancedLLMResponse>;
18
+ private invokeInternal;
19
+ private validateRequest;
20
+ private extractOutboundPrompt;
21
+ private looksLikeConfigJSON;
22
+ }