@juspay/neurolink 7.6.0 → 7.7.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.
- package/CHANGELOG.md +14 -2
- package/README.md +79 -4
- package/dist/cli/commands/config.d.ts +275 -3
- package/dist/cli/commands/config.js +121 -0
- package/dist/cli/commands/mcp.js +77 -28
- package/dist/cli/factories/commandFactory.js +359 -6
- package/dist/core/analytics.js +7 -27
- package/dist/core/baseProvider.js +43 -4
- package/dist/core/constants.d.ts +46 -0
- package/dist/core/constants.js +47 -0
- package/dist/core/dynamicModels.d.ts +16 -4
- package/dist/core/dynamicModels.js +130 -26
- package/dist/core/evaluation.js +5 -1
- package/dist/core/evaluationProviders.d.ts +6 -2
- package/dist/core/evaluationProviders.js +41 -125
- package/dist/core/factory.d.ts +5 -0
- package/dist/core/factory.js +62 -50
- package/dist/core/modelConfiguration.d.ts +246 -0
- package/dist/core/modelConfiguration.js +775 -0
- package/dist/core/types.d.ts +22 -3
- package/dist/core/types.js +5 -1
- package/dist/factories/providerRegistry.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/core/analytics.js +7 -27
- package/dist/lib/core/baseProvider.js +43 -4
- package/dist/lib/core/constants.d.ts +46 -0
- package/dist/lib/core/constants.js +47 -0
- package/dist/lib/core/dynamicModels.d.ts +16 -4
- package/dist/lib/core/dynamicModels.js +130 -26
- package/dist/lib/core/evaluation.js +5 -1
- package/dist/lib/core/evaluationProviders.d.ts +6 -2
- package/dist/lib/core/evaluationProviders.js +41 -125
- package/dist/lib/core/factory.d.ts +5 -0
- package/dist/lib/core/factory.js +63 -50
- package/dist/lib/core/modelConfiguration.d.ts +246 -0
- package/dist/lib/core/modelConfiguration.js +775 -0
- package/dist/lib/core/types.d.ts +22 -3
- package/dist/lib/core/types.js +5 -1
- package/dist/lib/factories/providerRegistry.js +3 -3
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/mcp/factory.d.ts +5 -5
- package/dist/lib/mcp/factory.js +2 -2
- package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/lib/mcp/servers/utilities/utilityServer.js +1 -1
- package/dist/lib/mcp/toolRegistry.js +2 -2
- package/dist/lib/neurolink.d.ts +168 -12
- package/dist/lib/neurolink.js +685 -123
- package/dist/lib/providers/anthropic.js +52 -2
- package/dist/lib/providers/googleAiStudio.js +4 -0
- package/dist/lib/providers/googleVertex.d.ts +75 -9
- package/dist/lib/providers/googleVertex.js +365 -46
- package/dist/lib/providers/huggingFace.d.ts +52 -11
- package/dist/lib/providers/huggingFace.js +180 -42
- package/dist/lib/providers/litellm.d.ts +9 -9
- package/dist/lib/providers/litellm.js +103 -16
- package/dist/lib/providers/ollama.d.ts +52 -17
- package/dist/lib/providers/ollama.js +276 -68
- package/dist/lib/sdk/toolRegistration.d.ts +42 -0
- package/dist/lib/sdk/toolRegistration.js +269 -27
- package/dist/lib/telemetry/telemetryService.d.ts +6 -0
- package/dist/lib/telemetry/telemetryService.js +38 -3
- package/dist/lib/types/contextTypes.d.ts +75 -11
- package/dist/lib/types/contextTypes.js +227 -1
- package/dist/lib/types/domainTypes.d.ts +62 -0
- package/dist/lib/types/domainTypes.js +5 -0
- package/dist/lib/types/generateTypes.d.ts +52 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/mcpTypes.d.ts +1 -1
- package/dist/lib/types/mcpTypes.js +1 -1
- package/dist/lib/types/streamTypes.d.ts +14 -0
- package/dist/lib/types/universalProviderOptions.d.ts +1 -1
- package/dist/lib/utils/errorHandling.d.ts +142 -0
- package/dist/lib/utils/errorHandling.js +316 -0
- package/dist/lib/utils/factoryProcessing.d.ts +74 -0
- package/dist/lib/utils/factoryProcessing.js +588 -0
- package/dist/lib/utils/optionsConversion.d.ts +54 -0
- package/dist/lib/utils/optionsConversion.js +126 -0
- package/dist/lib/utils/optionsUtils.d.ts +246 -0
- package/dist/lib/utils/optionsUtils.js +960 -0
- package/dist/lib/utils/providerHealth.d.ts +107 -0
- package/dist/lib/utils/providerHealth.js +507 -0
- package/dist/lib/utils/providerUtils.d.ts +17 -0
- package/dist/lib/utils/providerUtils.js +271 -16
- package/dist/lib/utils/timeout.js +1 -1
- package/dist/lib/utils/tokenLimits.d.ts +33 -0
- package/dist/lib/utils/tokenLimits.js +118 -0
- package/dist/mcp/factory.d.ts +5 -5
- package/dist/mcp/factory.js +2 -2
- package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/mcp/servers/utilities/utilityServer.js +1 -1
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/neurolink.d.ts +168 -12
- package/dist/neurolink.js +685 -123
- package/dist/providers/anthropic.js +52 -2
- package/dist/providers/googleAiStudio.js +4 -0
- package/dist/providers/googleVertex.d.ts +75 -9
- package/dist/providers/googleVertex.js +365 -46
- package/dist/providers/huggingFace.d.ts +52 -11
- package/dist/providers/huggingFace.js +181 -43
- package/dist/providers/litellm.d.ts +9 -9
- package/dist/providers/litellm.js +103 -16
- package/dist/providers/ollama.d.ts +52 -17
- package/dist/providers/ollama.js +276 -68
- package/dist/sdk/toolRegistration.d.ts +42 -0
- package/dist/sdk/toolRegistration.js +269 -27
- package/dist/telemetry/telemetryService.d.ts +6 -0
- package/dist/telemetry/telemetryService.js +38 -3
- package/dist/types/contextTypes.d.ts +75 -11
- package/dist/types/contextTypes.js +227 -2
- package/dist/types/domainTypes.d.ts +62 -0
- package/dist/types/domainTypes.js +5 -0
- package/dist/types/generateTypes.d.ts +52 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mcpTypes.d.ts +1 -1
- package/dist/types/mcpTypes.js +1 -1
- package/dist/types/streamTypes.d.ts +14 -0
- package/dist/types/universalProviderOptions.d.ts +1 -1
- package/dist/types/universalProviderOptions.js +0 -1
- package/dist/utils/errorHandling.d.ts +142 -0
- package/dist/utils/errorHandling.js +316 -0
- package/dist/utils/factoryProcessing.d.ts +74 -0
- package/dist/utils/factoryProcessing.js +588 -0
- package/dist/utils/optionsConversion.d.ts +54 -0
- package/dist/utils/optionsConversion.js +126 -0
- package/dist/utils/optionsUtils.d.ts +246 -0
- package/dist/utils/optionsUtils.js +960 -0
- package/dist/utils/providerHealth.d.ts +107 -0
- package/dist/utils/providerHealth.js +507 -0
- package/dist/utils/providerUtils.d.ts +17 -0
- package/dist/utils/providerUtils.js +271 -16
- package/dist/utils/timeout.js +1 -1
- package/dist/utils/tokenLimits.d.ts +33 -0
- package/dist/utils/tokenLimits.js +118 -0
- package/package.json +2 -2
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Configuration System
|
|
3
|
+
*
|
|
4
|
+
* Replaces hardcoded model-specific logic with configurable, runtime-updateable configurations.
|
|
5
|
+
* This addresses GitHub Copilot review comment about making model-specific logic configuration-based.
|
|
6
|
+
*/
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
/**
|
|
11
|
+
* Model name constants - extracted from hardcoded values for better maintainability
|
|
12
|
+
* These constants can be overridden by environment variables
|
|
13
|
+
*/
|
|
14
|
+
export const MODEL_NAMES = {
|
|
15
|
+
// Google AI Models
|
|
16
|
+
GOOGLE_AI: {
|
|
17
|
+
FAST: "gemini-2.5-flash",
|
|
18
|
+
BALANCED: "gemini-2.5-pro",
|
|
19
|
+
QUALITY: "gemini-2.5-pro",
|
|
20
|
+
},
|
|
21
|
+
// Google Vertex Models
|
|
22
|
+
GOOGLE_VERTEX: {
|
|
23
|
+
FAST: "gemini-2.5-flash",
|
|
24
|
+
BALANCED: "gemini-2.5-pro",
|
|
25
|
+
QUALITY: "gemini-2.5-pro",
|
|
26
|
+
},
|
|
27
|
+
// OpenAI Models
|
|
28
|
+
OPENAI: {
|
|
29
|
+
FAST: "gpt-4o-mini",
|
|
30
|
+
BALANCED: "gpt-4o",
|
|
31
|
+
QUALITY: "gpt-4o",
|
|
32
|
+
},
|
|
33
|
+
// Anthropic Models
|
|
34
|
+
ANTHROPIC: {
|
|
35
|
+
FAST: "claude-3-haiku-20240307",
|
|
36
|
+
BALANCED: "claude-3-sonnet-20240229",
|
|
37
|
+
QUALITY: "claude-3-5-sonnet-20241022",
|
|
38
|
+
},
|
|
39
|
+
// Vertex AI Models (legacy alias)
|
|
40
|
+
VERTEX: {
|
|
41
|
+
FAST: "gemini-2.5-flash",
|
|
42
|
+
BALANCED: "gemini-2.5-pro",
|
|
43
|
+
QUALITY: "gemini-2.5-pro",
|
|
44
|
+
},
|
|
45
|
+
// AWS Bedrock Models
|
|
46
|
+
BEDROCK: {
|
|
47
|
+
FAST: "anthropic.claude-3-haiku-20240307-v1:0",
|
|
48
|
+
BALANCED: "anthropic.claude-3-sonnet-20240229-v1:0",
|
|
49
|
+
QUALITY: "anthropic.claude-3-opus-20240229-v1:0",
|
|
50
|
+
},
|
|
51
|
+
// Azure OpenAI Models
|
|
52
|
+
AZURE: {
|
|
53
|
+
FAST: "gpt-4o-mini",
|
|
54
|
+
BALANCED: "gpt-4o",
|
|
55
|
+
QUALITY: "gpt-4o",
|
|
56
|
+
},
|
|
57
|
+
// Ollama Models
|
|
58
|
+
OLLAMA: {
|
|
59
|
+
FAST: "llama3.2:latest",
|
|
60
|
+
BALANCED: "llama3.1:8b",
|
|
61
|
+
QUALITY: "llama3.1:70b",
|
|
62
|
+
},
|
|
63
|
+
// HuggingFace Models
|
|
64
|
+
HUGGINGFACE: {
|
|
65
|
+
FAST: "microsoft/DialoGPT-medium",
|
|
66
|
+
BALANCED: "microsoft/DialoGPT-large",
|
|
67
|
+
QUALITY: "meta-llama/Llama-2-7b-chat-hf",
|
|
68
|
+
},
|
|
69
|
+
// Mistral Models
|
|
70
|
+
MISTRAL: {
|
|
71
|
+
FAST: "mistral-small-latest",
|
|
72
|
+
BALANCED: "mistral-medium-latest",
|
|
73
|
+
QUALITY: "mistral-large-latest",
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Model configuration manager
|
|
78
|
+
*/
|
|
79
|
+
export class ModelConfigurationManager {
|
|
80
|
+
static instance;
|
|
81
|
+
configurations = new Map();
|
|
82
|
+
configSource = "default";
|
|
83
|
+
lastUpdated = Date.now();
|
|
84
|
+
constructor() {
|
|
85
|
+
this.loadDefaultConfigurations();
|
|
86
|
+
}
|
|
87
|
+
static getInstance() {
|
|
88
|
+
if (!ModelConfigurationManager.instance) {
|
|
89
|
+
ModelConfigurationManager.instance = new ModelConfigurationManager();
|
|
90
|
+
}
|
|
91
|
+
return ModelConfigurationManager.instance;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Load default configurations (replaces hardcoded values)
|
|
95
|
+
*/
|
|
96
|
+
loadDefaultConfigurations() {
|
|
97
|
+
// Default provider configurations - these can be overridden
|
|
98
|
+
const defaultConfigs = {
|
|
99
|
+
"google-ai": {
|
|
100
|
+
provider: "google-ai",
|
|
101
|
+
models: {
|
|
102
|
+
fast: this.getConfigValue("GOOGLE_AI_FAST_MODEL", MODEL_NAMES.GOOGLE_AI.FAST),
|
|
103
|
+
balanced: this.getConfigValue("GOOGLE_AI_BALANCED_MODEL", MODEL_NAMES.GOOGLE_AI.BALANCED),
|
|
104
|
+
quality: this.getConfigValue("GOOGLE_AI_QUALITY_MODEL", MODEL_NAMES.GOOGLE_AI.QUALITY),
|
|
105
|
+
},
|
|
106
|
+
defaultCost: {
|
|
107
|
+
input: this.parseFloat(process.env.GOOGLE_AI_DEFAULT_INPUT_COST, 0.000075),
|
|
108
|
+
output: this.parseFloat(process.env.GOOGLE_AI_DEFAULT_OUTPUT_COST, 0.0003),
|
|
109
|
+
},
|
|
110
|
+
requiredEnvVars: ["GOOGLE_AI_API_KEY"],
|
|
111
|
+
performance: {
|
|
112
|
+
speed: this.parseInt(process.env.GOOGLE_AI_SPEED_RATING, 3),
|
|
113
|
+
quality: this.parseInt(process.env.GOOGLE_AI_QUALITY_RATING, 3),
|
|
114
|
+
cost: this.parseInt(process.env.GOOGLE_AI_COST_RATING, 3),
|
|
115
|
+
},
|
|
116
|
+
modelBehavior: {
|
|
117
|
+
maxTokensIssues: this.getConfigArray("GOOGLE_AI_MAX_TOKENS_ISSUES", [
|
|
118
|
+
MODEL_NAMES.GOOGLE_AI.FAST,
|
|
119
|
+
MODEL_NAMES.GOOGLE_AI.BALANCED,
|
|
120
|
+
]),
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
"google-vertex": {
|
|
124
|
+
provider: "google-vertex",
|
|
125
|
+
models: {
|
|
126
|
+
fast: this.getConfigValue("GOOGLE_VERTEX_FAST_MODEL", MODEL_NAMES.GOOGLE_VERTEX.FAST),
|
|
127
|
+
balanced: this.getConfigValue("GOOGLE_VERTEX_BALANCED_MODEL", MODEL_NAMES.GOOGLE_VERTEX.BALANCED),
|
|
128
|
+
quality: this.getConfigValue("GOOGLE_VERTEX_QUALITY_MODEL", MODEL_NAMES.GOOGLE_VERTEX.QUALITY),
|
|
129
|
+
},
|
|
130
|
+
defaultCost: {
|
|
131
|
+
input: this.parseFloat(process.env.GOOGLE_VERTEX_DEFAULT_INPUT_COST, 0.000075),
|
|
132
|
+
output: this.parseFloat(process.env.GOOGLE_VERTEX_DEFAULT_OUTPUT_COST, 0.0003),
|
|
133
|
+
},
|
|
134
|
+
requiredEnvVars: ["GOOGLE_VERTEX_PROJECT_ID", "GOOGLE_VERTEX_LOCATION"],
|
|
135
|
+
performance: {
|
|
136
|
+
speed: this.parseInt(process.env.GOOGLE_VERTEX_SPEED_RATING, 3),
|
|
137
|
+
quality: this.parseInt(process.env.GOOGLE_VERTEX_QUALITY_RATING, 3),
|
|
138
|
+
cost: this.parseInt(process.env.GOOGLE_VERTEX_COST_RATING, 3),
|
|
139
|
+
},
|
|
140
|
+
modelBehavior: {
|
|
141
|
+
maxTokensIssues: this.getConfigArray("GOOGLE_VERTEX_MAX_TOKENS_ISSUES", [
|
|
142
|
+
MODEL_NAMES.GOOGLE_VERTEX.FAST,
|
|
143
|
+
MODEL_NAMES.GOOGLE_VERTEX.BALANCED,
|
|
144
|
+
]),
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
openai: {
|
|
148
|
+
provider: "openai",
|
|
149
|
+
models: {
|
|
150
|
+
fast: this.getConfigValue("OPENAI_FAST_MODEL", MODEL_NAMES.OPENAI.FAST),
|
|
151
|
+
balanced: this.getConfigValue("OPENAI_BALANCED_MODEL", MODEL_NAMES.OPENAI.BALANCED),
|
|
152
|
+
quality: this.getConfigValue("OPENAI_QUALITY_MODEL", MODEL_NAMES.OPENAI.QUALITY),
|
|
153
|
+
},
|
|
154
|
+
defaultCost: {
|
|
155
|
+
input: this.parseFloat(process.env.OPENAI_DEFAULT_INPUT_COST, 0.00015),
|
|
156
|
+
output: this.parseFloat(process.env.OPENAI_DEFAULT_OUTPUT_COST, 0.0006),
|
|
157
|
+
},
|
|
158
|
+
requiredEnvVars: ["OPENAI_API_KEY"],
|
|
159
|
+
performance: {
|
|
160
|
+
speed: this.parseInt(process.env.OPENAI_SPEED_RATING, 2),
|
|
161
|
+
quality: this.parseInt(process.env.OPENAI_QUALITY_RATING, 3),
|
|
162
|
+
cost: this.parseInt(process.env.OPENAI_COST_RATING, 2),
|
|
163
|
+
},
|
|
164
|
+
modelBehavior: {
|
|
165
|
+
maxTokensIssues: this.getConfigArray("OPENAI_MAX_TOKENS_ISSUES", []),
|
|
166
|
+
specialHandling: this.getConfigObject("OPENAI_SPECIAL_HANDLING", {}),
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
anthropic: {
|
|
170
|
+
provider: "anthropic",
|
|
171
|
+
models: {
|
|
172
|
+
fast: this.getConfigValue("ANTHROPIC_FAST_MODEL", MODEL_NAMES.ANTHROPIC.FAST),
|
|
173
|
+
balanced: this.getConfigValue("ANTHROPIC_BALANCED_MODEL", MODEL_NAMES.ANTHROPIC.BALANCED),
|
|
174
|
+
quality: this.getConfigValue("ANTHROPIC_QUALITY_MODEL", MODEL_NAMES.ANTHROPIC.QUALITY),
|
|
175
|
+
},
|
|
176
|
+
defaultCost: {
|
|
177
|
+
input: this.parseFloat(process.env.ANTHROPIC_DEFAULT_INPUT_COST, 0.00025),
|
|
178
|
+
output: this.parseFloat(process.env.ANTHROPIC_DEFAULT_OUTPUT_COST, 0.00125),
|
|
179
|
+
},
|
|
180
|
+
requiredEnvVars: ["ANTHROPIC_API_KEY"],
|
|
181
|
+
performance: {
|
|
182
|
+
speed: this.parseInt(process.env.ANTHROPIC_SPEED_RATING, 2),
|
|
183
|
+
quality: this.parseInt(process.env.ANTHROPIC_QUALITY_RATING, 3),
|
|
184
|
+
cost: this.parseInt(process.env.ANTHROPIC_COST_RATING, 2),
|
|
185
|
+
},
|
|
186
|
+
modelBehavior: {
|
|
187
|
+
maxTokensIssues: this.getConfigArray("ANTHROPIC_MAX_TOKENS_ISSUES", []),
|
|
188
|
+
specialHandling: this.getConfigObject("ANTHROPIC_SPECIAL_HANDLING", {}),
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
vertex: {
|
|
192
|
+
provider: "vertex",
|
|
193
|
+
models: {
|
|
194
|
+
fast: this.getConfigValue("VERTEX_FAST_MODEL", MODEL_NAMES.VERTEX.FAST),
|
|
195
|
+
balanced: this.getConfigValue("VERTEX_BALANCED_MODEL", MODEL_NAMES.VERTEX.BALANCED),
|
|
196
|
+
quality: this.getConfigValue("VERTEX_QUALITY_MODEL", MODEL_NAMES.VERTEX.QUALITY),
|
|
197
|
+
},
|
|
198
|
+
defaultCost: {
|
|
199
|
+
input: this.parseFloat(process.env.VERTEX_DEFAULT_INPUT_COST, 0.000075),
|
|
200
|
+
output: this.parseFloat(process.env.VERTEX_DEFAULT_OUTPUT_COST, 0.0003),
|
|
201
|
+
},
|
|
202
|
+
requiredEnvVars: [
|
|
203
|
+
"GOOGLE_VERTEX_PROJECT",
|
|
204
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
205
|
+
],
|
|
206
|
+
performance: {
|
|
207
|
+
speed: this.parseInt(process.env.VERTEX_SPEED_RATING, 2),
|
|
208
|
+
quality: this.parseInt(process.env.VERTEX_QUALITY_RATING, 3),
|
|
209
|
+
cost: this.parseInt(process.env.VERTEX_COST_RATING, 3),
|
|
210
|
+
},
|
|
211
|
+
modelBehavior: {
|
|
212
|
+
maxTokensIssues: this.getConfigArray("VERTEX_MAX_TOKENS_ISSUES", [
|
|
213
|
+
MODEL_NAMES.VERTEX.FAST,
|
|
214
|
+
MODEL_NAMES.VERTEX.BALANCED,
|
|
215
|
+
]),
|
|
216
|
+
specialHandling: this.getConfigObject("VERTEX_SPECIAL_HANDLING", {}),
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
bedrock: {
|
|
220
|
+
provider: "bedrock",
|
|
221
|
+
models: {
|
|
222
|
+
fast: this.getConfigValue("BEDROCK_FAST_MODEL", MODEL_NAMES.BEDROCK.FAST),
|
|
223
|
+
balanced: this.getConfigValue("BEDROCK_BALANCED_MODEL", MODEL_NAMES.BEDROCK.BALANCED),
|
|
224
|
+
quality: this.getConfigValue("BEDROCK_QUALITY_MODEL", MODEL_NAMES.BEDROCK.QUALITY),
|
|
225
|
+
},
|
|
226
|
+
defaultCost: {
|
|
227
|
+
input: this.parseFloat(process.env.BEDROCK_DEFAULT_INPUT_COST, 0.00025),
|
|
228
|
+
output: this.parseFloat(process.env.BEDROCK_DEFAULT_OUTPUT_COST, 0.00125),
|
|
229
|
+
},
|
|
230
|
+
requiredEnvVars: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"],
|
|
231
|
+
performance: {
|
|
232
|
+
speed: this.parseInt(process.env.BEDROCK_SPEED_RATING, 2),
|
|
233
|
+
quality: this.parseInt(process.env.BEDROCK_QUALITY_RATING, 3),
|
|
234
|
+
cost: this.parseInt(process.env.BEDROCK_COST_RATING, 2),
|
|
235
|
+
},
|
|
236
|
+
modelBehavior: {
|
|
237
|
+
maxTokensIssues: this.getConfigArray("BEDROCK_MAX_TOKENS_ISSUES", []),
|
|
238
|
+
specialHandling: this.getConfigObject("BEDROCK_SPECIAL_HANDLING", {}),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
azure: {
|
|
242
|
+
provider: "azure",
|
|
243
|
+
models: {
|
|
244
|
+
fast: this.getConfigValue("AZURE_FAST_MODEL", MODEL_NAMES.AZURE.FAST),
|
|
245
|
+
balanced: this.getConfigValue("AZURE_BALANCED_MODEL", MODEL_NAMES.AZURE.BALANCED),
|
|
246
|
+
quality: this.getConfigValue("AZURE_QUALITY_MODEL", MODEL_NAMES.AZURE.QUALITY),
|
|
247
|
+
},
|
|
248
|
+
defaultCost: {
|
|
249
|
+
input: this.parseFloat(process.env.AZURE_DEFAULT_INPUT_COST, 0.00015),
|
|
250
|
+
output: this.parseFloat(process.env.AZURE_DEFAULT_OUTPUT_COST, 0.0006),
|
|
251
|
+
},
|
|
252
|
+
requiredEnvVars: ["AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT"],
|
|
253
|
+
performance: {
|
|
254
|
+
speed: this.parseInt(process.env.AZURE_SPEED_RATING, 2),
|
|
255
|
+
quality: this.parseInt(process.env.AZURE_QUALITY_RATING, 3),
|
|
256
|
+
cost: this.parseInt(process.env.AZURE_COST_RATING, 2),
|
|
257
|
+
},
|
|
258
|
+
modelBehavior: {
|
|
259
|
+
maxTokensIssues: this.getConfigArray("AZURE_MAX_TOKENS_ISSUES", []),
|
|
260
|
+
specialHandling: this.getConfigObject("AZURE_SPECIAL_HANDLING", {}),
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
ollama: {
|
|
264
|
+
provider: "ollama",
|
|
265
|
+
models: {
|
|
266
|
+
fast: this.getConfigValue("OLLAMA_FAST_MODEL", MODEL_NAMES.OLLAMA.FAST),
|
|
267
|
+
balanced: this.getConfigValue("OLLAMA_BALANCED_MODEL", MODEL_NAMES.OLLAMA.BALANCED),
|
|
268
|
+
quality: this.getConfigValue("OLLAMA_QUALITY_MODEL", MODEL_NAMES.OLLAMA.QUALITY),
|
|
269
|
+
},
|
|
270
|
+
defaultCost: {
|
|
271
|
+
input: 0, // Local models are free
|
|
272
|
+
output: 0,
|
|
273
|
+
},
|
|
274
|
+
requiredEnvVars: [], // No API key needed
|
|
275
|
+
performance: {
|
|
276
|
+
speed: this.parseInt(process.env.OLLAMA_SPEED_RATING, 1),
|
|
277
|
+
quality: this.parseInt(process.env.OLLAMA_QUALITY_RATING, 2),
|
|
278
|
+
cost: this.parseInt(process.env.OLLAMA_COST_RATING, 3),
|
|
279
|
+
},
|
|
280
|
+
modelBehavior: {
|
|
281
|
+
maxTokensIssues: this.getConfigArray("OLLAMA_MAX_TOKENS_ISSUES", []),
|
|
282
|
+
specialHandling: this.getConfigObject("OLLAMA_SPECIAL_HANDLING", {}),
|
|
283
|
+
// Tool-capable models configuration (replaces hardcoded list in ollama.ts)
|
|
284
|
+
toolCapableModels: this.getConfigArray("OLLAMA_TOOL_CAPABLE_MODELS", [
|
|
285
|
+
// Llama 3.1 series (excellent tool calling)
|
|
286
|
+
"llama3.1:8b-instruct",
|
|
287
|
+
"llama3.1:70b-instruct",
|
|
288
|
+
"llama3.1",
|
|
289
|
+
// Mistral series (reliable function calling)
|
|
290
|
+
"mistral:7b-instruct",
|
|
291
|
+
"mistral-nemo:12b",
|
|
292
|
+
"mistral",
|
|
293
|
+
// Hermes series (specialized for tools)
|
|
294
|
+
"hermes3:8b",
|
|
295
|
+
"hermes2-pro",
|
|
296
|
+
// Function-calling specialized models
|
|
297
|
+
"firefunction-v2",
|
|
298
|
+
"firefunction",
|
|
299
|
+
// Code Llama (code-focused tools)
|
|
300
|
+
"codellama:34b-instruct",
|
|
301
|
+
"codellama:13b-instruct",
|
|
302
|
+
// Other capable models
|
|
303
|
+
"qwen2.5:14b-instruct",
|
|
304
|
+
"gemma2:27b-instruct",
|
|
305
|
+
]),
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
huggingface: {
|
|
309
|
+
provider: "huggingface",
|
|
310
|
+
models: {
|
|
311
|
+
fast: this.getConfigValue("HUGGINGFACE_FAST_MODEL", MODEL_NAMES.HUGGINGFACE.FAST),
|
|
312
|
+
balanced: this.getConfigValue("HUGGINGFACE_BALANCED_MODEL", MODEL_NAMES.HUGGINGFACE.BALANCED),
|
|
313
|
+
quality: this.getConfigValue("HUGGINGFACE_QUALITY_MODEL", MODEL_NAMES.HUGGINGFACE.QUALITY),
|
|
314
|
+
},
|
|
315
|
+
defaultCost: {
|
|
316
|
+
input: this.parseFloat(process.env.HUGGINGFACE_DEFAULT_INPUT_COST, 0.0002),
|
|
317
|
+
output: this.parseFloat(process.env.HUGGINGFACE_DEFAULT_OUTPUT_COST, 0.0006),
|
|
318
|
+
},
|
|
319
|
+
requiredEnvVars: ["HUGGINGFACE_API_KEY"],
|
|
320
|
+
performance: {
|
|
321
|
+
speed: this.parseInt(process.env.HUGGINGFACE_SPEED_RATING, 1),
|
|
322
|
+
quality: this.parseInt(process.env.HUGGINGFACE_QUALITY_RATING, 2),
|
|
323
|
+
cost: this.parseInt(process.env.HUGGINGFACE_COST_RATING, 2),
|
|
324
|
+
},
|
|
325
|
+
modelBehavior: {
|
|
326
|
+
maxTokensIssues: this.getConfigArray("HUGGINGFACE_MAX_TOKENS_ISSUES", []),
|
|
327
|
+
specialHandling: this.getConfigObject("HUGGINGFACE_SPECIAL_HANDLING", {}),
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
mistral: {
|
|
331
|
+
provider: "mistral",
|
|
332
|
+
models: {
|
|
333
|
+
fast: this.getConfigValue("MISTRAL_FAST_MODEL", MODEL_NAMES.MISTRAL.FAST),
|
|
334
|
+
balanced: this.getConfigValue("MISTRAL_BALANCED_MODEL", MODEL_NAMES.MISTRAL.BALANCED),
|
|
335
|
+
quality: this.getConfigValue("MISTRAL_QUALITY_MODEL", MODEL_NAMES.MISTRAL.QUALITY),
|
|
336
|
+
},
|
|
337
|
+
defaultCost: {
|
|
338
|
+
input: this.parseFloat(process.env.MISTRAL_DEFAULT_INPUT_COST, 0.0002),
|
|
339
|
+
output: this.parseFloat(process.env.MISTRAL_DEFAULT_OUTPUT_COST, 0.0006),
|
|
340
|
+
},
|
|
341
|
+
requiredEnvVars: ["MISTRAL_API_KEY"],
|
|
342
|
+
performance: {
|
|
343
|
+
speed: this.parseInt(process.env.MISTRAL_SPEED_RATING, 2),
|
|
344
|
+
quality: this.parseInt(process.env.MISTRAL_QUALITY_RATING, 2),
|
|
345
|
+
cost: this.parseInt(process.env.MISTRAL_COST_RATING, 2),
|
|
346
|
+
},
|
|
347
|
+
modelBehavior: {
|
|
348
|
+
maxTokensIssues: this.getConfigArray("MISTRAL_MAX_TOKENS_ISSUES", []),
|
|
349
|
+
specialHandling: this.getConfigObject("MISTRAL_SPECIAL_HANDLING", {}),
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
// Load configurations
|
|
354
|
+
for (const [provider, config] of Object.entries(defaultConfigs)) {
|
|
355
|
+
this.configurations.set(provider, config);
|
|
356
|
+
}
|
|
357
|
+
logger.debug(`Loaded ${this.configurations.size} provider configurations from ${this.configSource}`);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Helper method to get configuration value with fallback and validation
|
|
361
|
+
*/
|
|
362
|
+
getConfigValue(envVar, defaultValue) {
|
|
363
|
+
const value = process.env[envVar];
|
|
364
|
+
if (value && !this.isValidConfigValue(value)) {
|
|
365
|
+
logger.warn(`Environment variable ${envVar} has an invalid value: "${value}". Falling back to default value.`);
|
|
366
|
+
return defaultValue;
|
|
367
|
+
}
|
|
368
|
+
return value || defaultValue;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Validate configuration values for security and correctness
|
|
372
|
+
*/
|
|
373
|
+
isValidConfigValue(value) {
|
|
374
|
+
// Basic validation rules for security-sensitive configuration values
|
|
375
|
+
// Check for potentially dangerous characters (script injection prevention)
|
|
376
|
+
const dangerousChars = /[<>;"'`${}]/;
|
|
377
|
+
if (dangerousChars.test(value)) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
// Check for excessively long values (DoS prevention)
|
|
381
|
+
if (value.length > 500) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
// Check for null bytes (security)
|
|
385
|
+
if (value.includes("\0")) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
// Check for control characters except newlines and tabs
|
|
389
|
+
// Using String.fromCharCode to avoid ESLint control character error
|
|
390
|
+
const controlChars = new RegExp(`[${String.fromCharCode(0x00)}-${String.fromCharCode(0x08)}${String.fromCharCode(0x0b)}${String.fromCharCode(0x0c)}${String.fromCharCode(0x0e)}-${String.fromCharCode(0x1f)}${String.fromCharCode(0x7f)}]`);
|
|
391
|
+
if (controlChars.test(value)) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Helper method to get configuration array with fallback
|
|
398
|
+
* Parses comma-separated environment variable values
|
|
399
|
+
*/
|
|
400
|
+
getConfigArray(envVar, defaultValue) {
|
|
401
|
+
const envValue = process.env[envVar];
|
|
402
|
+
if (!envValue) {
|
|
403
|
+
return defaultValue;
|
|
404
|
+
}
|
|
405
|
+
return envValue
|
|
406
|
+
.split(",")
|
|
407
|
+
.map((item) => item.trim())
|
|
408
|
+
.filter(Boolean);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Helper method to parse float with fallback
|
|
412
|
+
*/
|
|
413
|
+
parseFloat(value, defaultValue) {
|
|
414
|
+
if (!value) {
|
|
415
|
+
return defaultValue;
|
|
416
|
+
}
|
|
417
|
+
const parsed = Number.parseFloat(value);
|
|
418
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Helper method to parse int with fallback
|
|
422
|
+
*/
|
|
423
|
+
parseInt(value, defaultValue) {
|
|
424
|
+
if (!value) {
|
|
425
|
+
return defaultValue;
|
|
426
|
+
}
|
|
427
|
+
const parsed = Number.parseInt(value, 10);
|
|
428
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Helper method to get configuration object with fallback
|
|
432
|
+
* Parses JSON environment variable values
|
|
433
|
+
*/
|
|
434
|
+
getConfigObject(envVar, defaultValue) {
|
|
435
|
+
const envValue = process.env[envVar];
|
|
436
|
+
if (!envValue) {
|
|
437
|
+
return defaultValue;
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
const parsed = JSON.parse(envValue);
|
|
441
|
+
return typeof parsed === "object" && parsed !== null
|
|
442
|
+
? parsed
|
|
443
|
+
: defaultValue;
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
logger.warn(`Invalid JSON in environment variable ${envVar}, using default`);
|
|
447
|
+
return defaultValue;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Get provider configuration
|
|
452
|
+
*/
|
|
453
|
+
getProviderConfig(provider) {
|
|
454
|
+
return this.configurations.get(provider) || null;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Get all provider configurations
|
|
458
|
+
*/
|
|
459
|
+
getAllConfigurations() {
|
|
460
|
+
return new Map(this.configurations);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Update provider configuration (runtime updates)
|
|
464
|
+
*/
|
|
465
|
+
updateProviderConfig(provider, config) {
|
|
466
|
+
this.configurations.set(provider, config);
|
|
467
|
+
this.lastUpdated = Date.now();
|
|
468
|
+
this.configSource = "dynamic";
|
|
469
|
+
logger.debug(`Updated configuration for provider: ${provider}`);
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Load configurations from external source
|
|
473
|
+
*/
|
|
474
|
+
loadConfigurationsFromFile(configPath) {
|
|
475
|
+
try {
|
|
476
|
+
// Check if file exists
|
|
477
|
+
if (!fs.existsSync(configPath)) {
|
|
478
|
+
throw new Error(`Configuration file not found: ${configPath}`);
|
|
479
|
+
}
|
|
480
|
+
// Read and parse configuration file
|
|
481
|
+
const configContent = fs.readFileSync(configPath, "utf8");
|
|
482
|
+
const fileExtension = path.extname(configPath).toLowerCase();
|
|
483
|
+
let configData;
|
|
484
|
+
if (fileExtension === ".json") {
|
|
485
|
+
configData = JSON.parse(configContent);
|
|
486
|
+
}
|
|
487
|
+
else if (fileExtension === ".yaml" || fileExtension === ".yml") {
|
|
488
|
+
// Basic YAML parsing for simple configurations
|
|
489
|
+
// For full YAML support, would need a proper YAML library
|
|
490
|
+
try {
|
|
491
|
+
configData = JSON.parse(configContent);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
// Simple YAML-to-JSON conversion for basic cases
|
|
495
|
+
const yamlLines = configContent.split("\n");
|
|
496
|
+
const jsonObj = {};
|
|
497
|
+
for (const line of yamlLines) {
|
|
498
|
+
const trimmedLine = line.trim();
|
|
499
|
+
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
500
|
+
const colonIndex = trimmedLine.indexOf(":");
|
|
501
|
+
if (colonIndex > 0) {
|
|
502
|
+
const key = trimmedLine.substring(0, colonIndex).trim();
|
|
503
|
+
const value = trimmedLine.substring(colonIndex + 1).trim();
|
|
504
|
+
// Basic type conversion
|
|
505
|
+
if (value === "true") {
|
|
506
|
+
jsonObj[key] = true;
|
|
507
|
+
}
|
|
508
|
+
else if (value === "false") {
|
|
509
|
+
jsonObj[key] = false;
|
|
510
|
+
}
|
|
511
|
+
else if (!isNaN(Number(value))) {
|
|
512
|
+
jsonObj[key] = Number(value);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
jsonObj[key] = value.replace(/['"]/g, "");
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
configData = jsonObj;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
throw new Error(`Unsupported configuration file format: ${fileExtension}. Supported formats: .json, .yaml, .yml`);
|
|
525
|
+
}
|
|
526
|
+
// Validate configuration structure
|
|
527
|
+
if (!configData || typeof configData !== "object") {
|
|
528
|
+
throw new Error("Invalid configuration format: must be an object");
|
|
529
|
+
}
|
|
530
|
+
const config = configData;
|
|
531
|
+
// Load provider configurations from file
|
|
532
|
+
if (config.providers && typeof config.providers === "object") {
|
|
533
|
+
const providers = config.providers;
|
|
534
|
+
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
535
|
+
if (this.isValidProviderConfig(providerConfig)) {
|
|
536
|
+
this.configurations.set(providerName, providerConfig);
|
|
537
|
+
logger.debug(`Loaded configuration for provider: ${providerName}`);
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
logger.warn(`Invalid configuration for provider: ${providerName}, skipping`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
// Load global model name overrides
|
|
545
|
+
if (config.modelNames && typeof config.modelNames === "object") {
|
|
546
|
+
const modelNames = config.modelNames;
|
|
547
|
+
this.applyModelNameOverrides(modelNames);
|
|
548
|
+
}
|
|
549
|
+
// Load global defaults
|
|
550
|
+
if (config.defaults && typeof config.defaults === "object") {
|
|
551
|
+
const defaults = config.defaults;
|
|
552
|
+
this.applyGlobalDefaults(defaults);
|
|
553
|
+
}
|
|
554
|
+
this.configSource = "file";
|
|
555
|
+
this.lastUpdated = Date.now();
|
|
556
|
+
logger.info(`Successfully loaded configurations from file: ${configPath}`);
|
|
557
|
+
logger.debug(`Loaded ${this.configurations.size} provider configurations`);
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
561
|
+
logger.error(`Failed to load configurations from file: ${errorMessage}`);
|
|
562
|
+
throw new Error(`Configuration loading failed: ${errorMessage}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Validate provider configuration structure
|
|
567
|
+
*/
|
|
568
|
+
isValidProviderConfig(config) {
|
|
569
|
+
if (!config || typeof config !== "object") {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
const providerConfig = config;
|
|
573
|
+
// Check required fields
|
|
574
|
+
const requiredFields = [
|
|
575
|
+
"provider",
|
|
576
|
+
"models",
|
|
577
|
+
"defaultCost",
|
|
578
|
+
"requiredEnvVars",
|
|
579
|
+
"performance",
|
|
580
|
+
];
|
|
581
|
+
for (const field of requiredFields) {
|
|
582
|
+
if (!(field in providerConfig)) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
// Validate models structure
|
|
587
|
+
if (typeof providerConfig.models !== "object" || !providerConfig.models) {
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
const models = providerConfig.models;
|
|
591
|
+
const requiredTiers = ["fast", "balanced", "quality"];
|
|
592
|
+
for (const tier of requiredTiers) {
|
|
593
|
+
if (typeof models[tier] !== "string") {
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// Validate defaultCost structure
|
|
598
|
+
if (typeof providerConfig.defaultCost !== "object" ||
|
|
599
|
+
!providerConfig.defaultCost) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
const defaultCost = providerConfig.defaultCost;
|
|
603
|
+
if (typeof defaultCost.input !== "number" ||
|
|
604
|
+
typeof defaultCost.output !== "number") {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
// Validate requiredEnvVars
|
|
608
|
+
if (!Array.isArray(providerConfig.requiredEnvVars)) {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
// Validate performance structure
|
|
612
|
+
if (typeof providerConfig.performance !== "object" ||
|
|
613
|
+
!providerConfig.performance) {
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
const performance = providerConfig.performance;
|
|
617
|
+
const perfFields = ["speed", "quality", "cost"];
|
|
618
|
+
for (const field of perfFields) {
|
|
619
|
+
if (typeof performance[field] !== "number") {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Apply model name overrides from configuration file
|
|
627
|
+
*/
|
|
628
|
+
applyModelNameOverrides(modelNames) {
|
|
629
|
+
try {
|
|
630
|
+
// Apply overrides to existing configurations
|
|
631
|
+
for (const [providerKey, providerModels] of Object.entries(modelNames)) {
|
|
632
|
+
if (typeof providerModels === "object" && providerModels) {
|
|
633
|
+
const models = providerModels;
|
|
634
|
+
const existingConfig = this.configurations.get(providerKey);
|
|
635
|
+
if (existingConfig) {
|
|
636
|
+
// Update existing configuration
|
|
637
|
+
for (const [tier, model] of Object.entries(models)) {
|
|
638
|
+
if (typeof model === "string" &&
|
|
639
|
+
["fast", "balanced", "quality"].includes(tier)) {
|
|
640
|
+
existingConfig.models[tier] = model;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
this.configurations.set(providerKey, existingConfig);
|
|
644
|
+
logger.debug(`Applied model name overrides for provider: ${providerKey}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
catch (error) {
|
|
650
|
+
logger.warn(`Failed to apply model name overrides: ${error instanceof Error ? error.message : String(error)}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Apply global default configurations
|
|
655
|
+
*/
|
|
656
|
+
applyGlobalDefaults(defaults) {
|
|
657
|
+
try {
|
|
658
|
+
// Apply global defaults to all existing configurations
|
|
659
|
+
for (const [providerName, config] of this.configurations.entries()) {
|
|
660
|
+
let updated = false;
|
|
661
|
+
// Apply default cost overrides
|
|
662
|
+
if (defaults.defaultCost && typeof defaults.defaultCost === "object") {
|
|
663
|
+
const defaultCost = defaults.defaultCost;
|
|
664
|
+
if (typeof defaultCost.input === "number") {
|
|
665
|
+
config.defaultCost.input = defaultCost.input;
|
|
666
|
+
updated = true;
|
|
667
|
+
}
|
|
668
|
+
if (typeof defaultCost.output === "number") {
|
|
669
|
+
config.defaultCost.output = defaultCost.output;
|
|
670
|
+
updated = true;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// Apply performance overrides
|
|
674
|
+
if (defaults.performance && typeof defaults.performance === "object") {
|
|
675
|
+
const performance = defaults.performance;
|
|
676
|
+
["speed", "quality", "cost"].forEach((field) => {
|
|
677
|
+
if (typeof performance[field] === "number") {
|
|
678
|
+
config.performance[field] =
|
|
679
|
+
performance[field];
|
|
680
|
+
updated = true;
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
if (updated) {
|
|
685
|
+
this.configurations.set(providerName, config);
|
|
686
|
+
logger.debug(`Applied global defaults to provider: ${providerName}`);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
logger.warn(`Failed to apply global defaults: ${error instanceof Error ? error.message : String(error)}`);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Get configuration metadata
|
|
696
|
+
*/
|
|
697
|
+
getConfigurationMeta() {
|
|
698
|
+
return {
|
|
699
|
+
source: this.configSource,
|
|
700
|
+
lastUpdated: this.lastUpdated,
|
|
701
|
+
providerCount: this.configurations.size,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Get model for specific tier and provider
|
|
706
|
+
*/
|
|
707
|
+
getModelForTier(provider, tier) {
|
|
708
|
+
const config = this.getProviderConfig(provider);
|
|
709
|
+
return config?.models[tier] || null;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Get cost information for provider and model
|
|
713
|
+
*/
|
|
714
|
+
getCostInfo(provider, model) {
|
|
715
|
+
const config = this.getProviderConfig(provider);
|
|
716
|
+
if (!config) {
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
// If specific model config exists, use it; otherwise use default
|
|
720
|
+
if (model && config.modelConfigs?.[model]) {
|
|
721
|
+
return config.modelConfigs[model].cost;
|
|
722
|
+
}
|
|
723
|
+
return config.defaultCost;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Check if provider is available (has required environment variables)
|
|
727
|
+
*/
|
|
728
|
+
isProviderAvailable(provider) {
|
|
729
|
+
const config = this.getProviderConfig(provider);
|
|
730
|
+
if (!config) {
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
if (config.requiredEnvVars.length === 0) {
|
|
734
|
+
return true; // No requirements (e.g., Ollama)
|
|
735
|
+
}
|
|
736
|
+
return config.requiredEnvVars.some((envVar) => Boolean(process.env[envVar]));
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Get available providers
|
|
740
|
+
*/
|
|
741
|
+
getAvailableProviders() {
|
|
742
|
+
return Array.from(this.configurations.values()).filter((config) => this.isProviderAvailable(config.provider));
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Global instance accessor
|
|
747
|
+
*/
|
|
748
|
+
export const modelConfig = ModelConfigurationManager.getInstance();
|
|
749
|
+
/**
|
|
750
|
+
* Convenience functions for common operations
|
|
751
|
+
*/
|
|
752
|
+
/**
|
|
753
|
+
* Get provider configuration (backwards compatible)
|
|
754
|
+
*/
|
|
755
|
+
export function getProviderConfig(provider) {
|
|
756
|
+
return modelConfig.getProviderConfig(provider);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Get model for tier (backwards compatible)
|
|
760
|
+
*/
|
|
761
|
+
export function getModelForTier(provider, tier) {
|
|
762
|
+
return modelConfig.getModelForTier(provider, tier);
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Get cost information (backwards compatible)
|
|
766
|
+
*/
|
|
767
|
+
export function getCostInfo(provider, model) {
|
|
768
|
+
return modelConfig.getCostInfo(provider, model);
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Check provider availability (backwards compatible)
|
|
772
|
+
*/
|
|
773
|
+
export function isProviderAvailable(provider) {
|
|
774
|
+
return modelConfig.isProviderAvailable(provider);
|
|
775
|
+
}
|