responses-proxy 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.
- package/README.md +56 -0
- package/cli.js +118 -0
- package/dist/anthropic-messages.js +383 -0
- package/dist/anthropic-messages.test.js +209 -0
- package/dist/audit-log.js +138 -0
- package/dist/audit-log.test.js +480 -0
- package/dist/billing-expiration.js +70 -0
- package/dist/billing-expiration.test.js +114 -0
- package/dist/billing.js +716 -0
- package/dist/billing.test.js +228 -0
- package/dist/chatgpt-oauth-store.js +240 -0
- package/dist/chatgpt-oauth-store.test.js +88 -0
- package/dist/chatgpt-oauth.js +118 -0
- package/dist/chatgpt-oauth.test.js +63 -0
- package/dist/chatgpt-provider-auth.js +60 -0
- package/dist/chatgpt-provider-auth.test.js +101 -0
- package/dist/client/app-icon.svg +17 -0
- package/dist/client/assets/index-C7Vvhst8.js +14 -0
- package/dist/client/assets/index-DpqgYK3L.css +1 -0
- package/dist/client/favicon.svg +17 -0
- package/dist/client/index.html +31 -0
- package/dist/client-config-apply.js +345 -0
- package/dist/client-config-apply.test.js +185 -0
- package/dist/client-token-limits.js +111 -0
- package/dist/client-token-limits.test.js +129 -0
- package/dist/codex-config.js +47 -0
- package/dist/codex-setup.js +87 -0
- package/dist/codex-setup.test.js +30 -0
- package/dist/config.js +314 -0
- package/dist/cost-analytics.js +31 -0
- package/dist/cost-analytics.test.js +38 -0
- package/dist/customer-key-access.js +126 -0
- package/dist/customer-key-access.test.js +178 -0
- package/dist/customer-keys.js +209 -0
- package/dist/customer-keys.test.js +68 -0
- package/dist/customer-usage.js +18 -0
- package/dist/customer-usage.test.js +55 -0
- package/dist/dashboard-auth.js +318 -0
- package/dist/dashboard-auth.test.js +133 -0
- package/dist/dashboard-serving.test.js +235 -0
- package/dist/error-response.js +174 -0
- package/dist/error-response.test.js +88 -0
- package/dist/forward.js +357 -0
- package/dist/health-websocket-manager.js +174 -0
- package/dist/http-rate-limit.js +36 -0
- package/dist/http-rate-limit.test.js +62 -0
- package/dist/kiro-auth.js +136 -0
- package/dist/kiro-auth.test.js +234 -0
- package/dist/kiro-codewhisperer.js +646 -0
- package/dist/kiro-codewhisperer.test.js +219 -0
- package/dist/kiro-device-login.js +338 -0
- package/dist/kiro-eventstream.js +219 -0
- package/dist/kiro-eventstream.test.js +79 -0
- package/dist/kiro-forward.js +401 -0
- package/dist/kiro-import-cli.js +69 -0
- package/dist/kiro-import.js +94 -0
- package/dist/kiro-import.test.js +125 -0
- package/dist/kiro-token-store.js +196 -0
- package/dist/kiro-token-store.test.js +207 -0
- package/dist/krouter-usage.js +243 -0
- package/dist/model-combo-repository.js +147 -0
- package/dist/model-routing.js +69 -0
- package/dist/model-routing.test.js +41 -0
- package/dist/normalize-request.js +531 -0
- package/dist/normalize-request.test.js +277 -0
- package/dist/omv-public-firewall.test.js +11 -0
- package/dist/package.json +17 -0
- package/dist/prompt-cache-state.js +146 -0
- package/dist/prompt-cache-state.test.js +71 -0
- package/dist/prompt-cache.js +229 -0
- package/dist/provider-health-service.js +404 -0
- package/dist/provider-request-parameters.js +107 -0
- package/dist/provider-request-parameters.test.js +26 -0
- package/dist/provider-routing.js +114 -0
- package/dist/provider-routing.test.js +64 -0
- package/dist/provider-usage.js +314 -0
- package/dist/request-timeout-policy.js +61 -0
- package/dist/request-timeout-policy.test.js +40 -0
- package/dist/response-cache.js +69 -0
- package/dist/response-cache.test.js +28 -0
- package/dist/routing-combo-repository.js +300 -0
- package/dist/routing-engine.js +377 -0
- package/dist/routing-integration.js +155 -0
- package/dist/routing-simulation-engine.js +326 -0
- package/dist/rtk-layer.js +483 -0
- package/dist/rtk-layer.test.js +198 -0
- package/dist/runtime-provider-repository.js +1742 -0
- package/dist/runtime-provider-repository.test.js +1177 -0
- package/dist/schema.js +118 -0
- package/dist/schema.test.js +16 -0
- package/dist/sepay-webhook.js +87 -0
- package/dist/sepay-webhook.test.js +142 -0
- package/dist/server-body-limit.test.js +35 -0
- package/dist/server-client-token-limits.test.js +161 -0
- package/dist/server-codex-config-setup.test.js +76 -0
- package/dist/server-http-rate-limit.test.js +80 -0
- package/dist/server-response-cache.test.js +105 -0
- package/dist/server-routes-alias.test.js +39 -0
- package/dist/server-sepay-webhook-security.test.js +59 -0
- package/dist/server.js +5906 -0
- package/dist/session-log.js +178 -0
- package/dist/tailnet-funnel-script.test.js +33 -0
- package/dist/telegram-bot/actions.js +118 -0
- package/dist/telegram-bot/admin-actions.js +103 -0
- package/dist/telegram-bot/auth.js +46 -0
- package/dist/telegram-bot/auth.test.js +1 -0
- package/dist/telegram-bot/bot-identity-repository.js +189 -0
- package/dist/telegram-bot/bot-identity-repository.test.js +78 -0
- package/dist/telegram-bot/callbacks.js +30 -0
- package/dist/telegram-bot/codex-config-delivery.js +38 -0
- package/dist/telegram-bot/codex-config-delivery.test.js +75 -0
- package/dist/telegram-bot/commands/accounts.js +140 -0
- package/dist/telegram-bot/commands/apikey.js +737 -0
- package/dist/telegram-bot/commands/apply.js +265 -0
- package/dist/telegram-bot/commands/clients.js +13 -0
- package/dist/telegram-bot/commands/customer-billing.test.js +271 -0
- package/dist/telegram-bot/commands/grant.js +138 -0
- package/dist/telegram-bot/commands/grant.test.js +217 -0
- package/dist/telegram-bot/commands/help.js +52 -0
- package/dist/telegram-bot/commands/me.js +53 -0
- package/dist/telegram-bot/commands/models.js +6 -0
- package/dist/telegram-bot/commands/oauth.js +64 -0
- package/dist/telegram-bot/commands/plans.js +96 -0
- package/dist/telegram-bot/commands/providers.js +27 -0
- package/dist/telegram-bot/commands/quota.js +10 -0
- package/dist/telegram-bot/commands/renew-user.js +139 -0
- package/dist/telegram-bot/commands/renew-user.test.js +184 -0
- package/dist/telegram-bot/commands/renew.js +1369 -0
- package/dist/telegram-bot/commands/renew.test.js +1633 -0
- package/dist/telegram-bot/commands/start.js +212 -0
- package/dist/telegram-bot/commands/start.test.js +280 -0
- package/dist/telegram-bot/commands/status.js +6 -0
- package/dist/telegram-bot/commands/tailscale.js +15 -0
- package/dist/telegram-bot/commands/tailscale.test.js +76 -0
- package/dist/telegram-bot/commands/test.js +51 -0
- package/dist/telegram-bot/commands/test.test.js +14 -0
- package/dist/telegram-bot/commands/usage.js +10 -0
- package/dist/telegram-bot/config.js +98 -0
- package/dist/telegram-bot/config.test.js +42 -0
- package/dist/telegram-bot/customer-actions.js +160 -0
- package/dist/telegram-bot/customer-api-keys.js +68 -0
- package/dist/telegram-bot/customer-billing.js +72 -0
- package/dist/telegram-bot/customer-workspace-repository.js +134 -0
- package/dist/telegram-bot/customer-workspace-repository.test.js +47 -0
- package/dist/telegram-bot/dashboard-login.js +39 -0
- package/dist/telegram-bot/format.js +140 -0
- package/dist/telegram-bot/grants.js +370 -0
- package/dist/telegram-bot/grants.test.js +290 -0
- package/dist/telegram-bot/index.js +85 -0
- package/dist/telegram-bot/message-cleanup.js +55 -0
- package/dist/telegram-bot/message-cleanup.test.js +77 -0
- package/dist/telegram-bot/message-format.js +45 -0
- package/dist/telegram-bot/message-format.test.js +10 -0
- package/dist/telegram-bot/proxy-client.js +174 -0
- package/dist/telegram-bot/rate-limit.js +95 -0
- package/dist/telegram-bot/rate-limit.test.js +58 -0
- package/dist/telegram-bot/sessions.js +171 -0
- package/dist/telegram-bot/sessions.test.js +107 -0
- package/dist/telegram-bot/telegram-adapter.js +126 -0
- package/dist/telegram-bot/worker.js +63 -0
- package/package.json +39 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
export class RoutingSimulationEngine {
|
|
2
|
+
routingEngine;
|
|
3
|
+
providerRepository;
|
|
4
|
+
constructor(routingEngine, providerRepository) {
|
|
5
|
+
this.routingEngine = routingEngine;
|
|
6
|
+
this.providerRepository = providerRepository;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run a comprehensive routing simulation
|
|
10
|
+
*/
|
|
11
|
+
async simulate(combo, request) {
|
|
12
|
+
const startTime = Date.now();
|
|
13
|
+
const routingPath = [];
|
|
14
|
+
const errors = [];
|
|
15
|
+
const recommendations = [];
|
|
16
|
+
try {
|
|
17
|
+
// Validate combo configuration
|
|
18
|
+
const validationErrors = this.validateCombo(combo);
|
|
19
|
+
if (validationErrors.length > 0) {
|
|
20
|
+
errors.push(...validationErrors);
|
|
21
|
+
}
|
|
22
|
+
// Create routing request
|
|
23
|
+
const routingRequest = {
|
|
24
|
+
route: request.route,
|
|
25
|
+
model: request.model,
|
|
26
|
+
tokenCount: request.tokenCount,
|
|
27
|
+
priority: request.priority || 'normal',
|
|
28
|
+
clientRoute: request.route,
|
|
29
|
+
startTime: Date.now()
|
|
30
|
+
};
|
|
31
|
+
// Add tier selection step
|
|
32
|
+
const enabledTiers = combo.tiers
|
|
33
|
+
.filter(tier => tier.isEnabled)
|
|
34
|
+
.sort((a, b) => a.priority - b.priority);
|
|
35
|
+
if (enabledTiers.length === 0) {
|
|
36
|
+
routingPath.push({
|
|
37
|
+
stepType: 'error',
|
|
38
|
+
success: false,
|
|
39
|
+
duration: 1,
|
|
40
|
+
reason: 'No enabled tiers available'
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
route: request.route,
|
|
45
|
+
metrics: {
|
|
46
|
+
totalDuration: Date.now() - startTime,
|
|
47
|
+
providerSelectionTime: 0,
|
|
48
|
+
fallbackCount: 0,
|
|
49
|
+
retryCount: 0
|
|
50
|
+
},
|
|
51
|
+
routingPath,
|
|
52
|
+
errors: [{ message: 'No enabled tiers available', suggestedAction: 'Enable at least one tier in the routing combo' }],
|
|
53
|
+
recommendations
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
routingPath.push({
|
|
57
|
+
stepType: 'tier_selection',
|
|
58
|
+
success: true,
|
|
59
|
+
duration: 2,
|
|
60
|
+
reason: `Found ${enabledTiers.length} enabled tier${enabledTiers.length !== 1 ? 's' : ''}`
|
|
61
|
+
});
|
|
62
|
+
// Simulate provider selection with potential failures
|
|
63
|
+
let result;
|
|
64
|
+
let retryCount = 0;
|
|
65
|
+
const maxRetries = request.maxRetries || 3;
|
|
66
|
+
do {
|
|
67
|
+
if (retryCount > 0) {
|
|
68
|
+
routingPath.push({
|
|
69
|
+
stepType: 'retry',
|
|
70
|
+
success: false,
|
|
71
|
+
duration: 100 + (retryCount * 50),
|
|
72
|
+
reason: `Retry attempt ${retryCount} after previous failure`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Simulate potential failures if requested
|
|
76
|
+
if (request.simulateFailures && Math.random() < 0.3 && retryCount < maxRetries) {
|
|
77
|
+
result = {
|
|
78
|
+
success: false,
|
|
79
|
+
error: 'Simulated provider failure',
|
|
80
|
+
selectionTime: Math.floor(Math.random() * 100) + 50,
|
|
81
|
+
fallbackCount: 0,
|
|
82
|
+
retryCount: retryCount
|
|
83
|
+
};
|
|
84
|
+
retryCount++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Perform actual routing
|
|
88
|
+
result = await this.routingEngine.selectProvider(combo, routingRequest);
|
|
89
|
+
break;
|
|
90
|
+
} while (!result.success && retryCount < maxRetries);
|
|
91
|
+
// Add provider selection steps based on result
|
|
92
|
+
if (result.success && result.provider) {
|
|
93
|
+
routingPath.push({
|
|
94
|
+
stepType: 'provider_selection',
|
|
95
|
+
success: true,
|
|
96
|
+
duration: result.selectionTime,
|
|
97
|
+
tierName: result.tier,
|
|
98
|
+
providerId: result.provider.id,
|
|
99
|
+
reason: `Selected provider with eligibility score ${result.eligibilityScore || 'unknown'}`
|
|
100
|
+
});
|
|
101
|
+
// Add fallback steps if any occurred
|
|
102
|
+
if (result.fallbackCount && result.fallbackCount > 0) {
|
|
103
|
+
for (let i = 0; i < result.fallbackCount; i++) {
|
|
104
|
+
routingPath.push({
|
|
105
|
+
stepType: 'fallback',
|
|
106
|
+
success: false,
|
|
107
|
+
duration: 50,
|
|
108
|
+
reason: `Fallback to next tier (attempt ${i + 1})`
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
routingPath.push({
|
|
115
|
+
stepType: 'error',
|
|
116
|
+
success: false,
|
|
117
|
+
duration: result.selectionTime,
|
|
118
|
+
reason: result.error || 'Provider selection failed'
|
|
119
|
+
});
|
|
120
|
+
errors.push({
|
|
121
|
+
message: result.error || 'No eligible providers found',
|
|
122
|
+
suggestedAction: 'Check provider health status and configuration'
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Generate recommendations based on simulation results
|
|
126
|
+
recommendations.push(...this.generateRecommendations(combo, result, routingPath));
|
|
127
|
+
// Calculate final metrics
|
|
128
|
+
const totalDuration = Date.now() - startTime;
|
|
129
|
+
const metrics = {
|
|
130
|
+
totalDuration,
|
|
131
|
+
providerSelectionTime: result.selectionTime,
|
|
132
|
+
fallbackCount: result.fallbackCount || 0,
|
|
133
|
+
retryCount
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
success: result.success,
|
|
137
|
+
selectedProvider: result.provider?.id,
|
|
138
|
+
selectedTier: result.tier,
|
|
139
|
+
route: request.route,
|
|
140
|
+
metrics,
|
|
141
|
+
routingPath,
|
|
142
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
143
|
+
recommendations: recommendations.length > 0 ? recommendations : undefined
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error('Simulation error:', error);
|
|
148
|
+
routingPath.push({
|
|
149
|
+
stepType: 'error',
|
|
150
|
+
success: false,
|
|
151
|
+
duration: Date.now() - startTime,
|
|
152
|
+
reason: error instanceof Error ? error.message : 'Unknown simulation error'
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
route: request.route,
|
|
157
|
+
metrics: {
|
|
158
|
+
totalDuration: Date.now() - startTime,
|
|
159
|
+
providerSelectionTime: 0,
|
|
160
|
+
fallbackCount: 0,
|
|
161
|
+
retryCount: 0
|
|
162
|
+
},
|
|
163
|
+
routingPath,
|
|
164
|
+
errors: [{
|
|
165
|
+
message: error instanceof Error ? error.message : 'Simulation failed',
|
|
166
|
+
suggestedAction: 'Check routing combo configuration and provider availability'
|
|
167
|
+
}]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validate routing combo configuration
|
|
173
|
+
*/
|
|
174
|
+
validateCombo(combo) {
|
|
175
|
+
const errors = [];
|
|
176
|
+
// Check if combo has tiers
|
|
177
|
+
if (!combo.tiers || combo.tiers.length === 0) {
|
|
178
|
+
errors.push({
|
|
179
|
+
message: 'Routing combo has no tiers configured',
|
|
180
|
+
suggestedAction: 'Add at least one tier to the routing combo'
|
|
181
|
+
});
|
|
182
|
+
return errors;
|
|
183
|
+
}
|
|
184
|
+
// Check for enabled tiers
|
|
185
|
+
const enabledTiers = combo.tiers.filter(tier => tier.isEnabled);
|
|
186
|
+
if (enabledTiers.length === 0) {
|
|
187
|
+
errors.push({
|
|
188
|
+
message: 'No tiers are enabled',
|
|
189
|
+
suggestedAction: 'Enable at least one tier in the routing combo'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Check tier priorities
|
|
193
|
+
const priorities = enabledTiers.map(tier => tier.priority);
|
|
194
|
+
const uniquePriorities = new Set(priorities);
|
|
195
|
+
if (priorities.length !== uniquePriorities.size) {
|
|
196
|
+
errors.push({
|
|
197
|
+
message: 'Multiple tiers have the same priority',
|
|
198
|
+
suggestedAction: 'Ensure each tier has a unique priority value'
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Check providers in tiers
|
|
202
|
+
for (const tier of enabledTiers) {
|
|
203
|
+
if (!tier.providers || tier.providers.length === 0) {
|
|
204
|
+
errors.push({
|
|
205
|
+
message: `Tier "${tier.name}" has no providers configured`,
|
|
206
|
+
suggestedAction: `Add at least one provider to tier "${tier.name}"`
|
|
207
|
+
});
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const enabledProviders = tier.providers.filter(p => p.isEnabled);
|
|
211
|
+
if (enabledProviders.length === 0) {
|
|
212
|
+
errors.push({
|
|
213
|
+
message: `Tier "${tier.name}" has no enabled providers`,
|
|
214
|
+
suggestedAction: `Enable at least one provider in tier "${tier.name}"`
|
|
215
|
+
});
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
// Check provider weights
|
|
219
|
+
const totalWeight = enabledProviders.reduce((sum, p) => sum + p.weight, 0);
|
|
220
|
+
if (Math.abs(totalWeight - 100) > 5) {
|
|
221
|
+
errors.push({
|
|
222
|
+
message: `Tier "${tier.name}" provider weights sum to ${totalWeight}%, not 100%`,
|
|
223
|
+
suggestedAction: `Adjust provider weights in tier "${tier.name}" to sum to 100%`
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
// Check if providers exist
|
|
227
|
+
for (const binding of enabledProviders) {
|
|
228
|
+
const provider = this.providerRepository.getProvider(binding.providerId);
|
|
229
|
+
if (!provider) {
|
|
230
|
+
errors.push({
|
|
231
|
+
message: `Provider "${binding.providerId}" in tier "${tier.name}" not found`,
|
|
232
|
+
suggestedAction: `Remove invalid provider or create provider "${binding.providerId}"`
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return errors;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Generate recommendations based on simulation results
|
|
241
|
+
*/
|
|
242
|
+
generateRecommendations(combo, result, routingPath) {
|
|
243
|
+
const recommendations = [];
|
|
244
|
+
// Analyze fallback patterns
|
|
245
|
+
if (result.fallbackCount && result.fallbackCount > 0) {
|
|
246
|
+
recommendations.push(`Consider reviewing tier ${combo.tiers[0]?.name || 'primary'} provider health - ${result.fallbackCount} fallback${result.fallbackCount !== 1 ? 's' : ''} occurred`);
|
|
247
|
+
}
|
|
248
|
+
// Analyze provider selection
|
|
249
|
+
if (result.success && result.eligibilityScore !== undefined) {
|
|
250
|
+
if (result.eligibilityScore < 70) {
|
|
251
|
+
recommendations.push(`Selected provider has low eligibility score (${result.eligibilityScore}). Consider improving provider health or configuration.`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Analyze tier configuration
|
|
255
|
+
const enabledTiers = combo.tiers.filter(tier => tier.isEnabled);
|
|
256
|
+
if (enabledTiers.length === 1) {
|
|
257
|
+
recommendations.push('Consider adding additional tiers for better fallback resilience');
|
|
258
|
+
}
|
|
259
|
+
// Analyze load balancing
|
|
260
|
+
if (combo.policies.loadBalancing === 'weighted') {
|
|
261
|
+
const hasUnbalancedTiers = enabledTiers.some(tier => {
|
|
262
|
+
const totalWeight = tier.providers.reduce((sum, p) => sum + p.weight, 0);
|
|
263
|
+
return Math.abs(totalWeight - 100) > 5;
|
|
264
|
+
});
|
|
265
|
+
if (hasUnbalancedTiers) {
|
|
266
|
+
recommendations.push('Some tiers have unbalanced provider weights. Consider rebalancing for optimal distribution.');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Analyze retry configuration
|
|
270
|
+
if (result.retryCount && result.retryCount > 0) {
|
|
271
|
+
recommendations.push(`${result.retryCount} retr${result.retryCount !== 1 ? 'ies' : 'y'} occurred. Consider adjusting retry policy or improving provider reliability.`);
|
|
272
|
+
}
|
|
273
|
+
// Performance recommendations
|
|
274
|
+
const totalDuration = routingPath.reduce((sum, step) => sum + step.duration, 0);
|
|
275
|
+
if (totalDuration > 1000) {
|
|
276
|
+
recommendations.push('Routing decision took longer than expected. Consider optimizing provider health checks or reducing fallback delays.');
|
|
277
|
+
}
|
|
278
|
+
return recommendations;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Run multiple simulations to get statistical insights
|
|
282
|
+
*/
|
|
283
|
+
async runBatchSimulation(combo, request, iterations = 10) {
|
|
284
|
+
const results = [];
|
|
285
|
+
// Run multiple simulations
|
|
286
|
+
for (let i = 0; i < iterations; i++) {
|
|
287
|
+
const result = await this.simulate(combo, request);
|
|
288
|
+
results.push(result);
|
|
289
|
+
}
|
|
290
|
+
// Calculate summary statistics
|
|
291
|
+
const successCount = results.filter(r => r.success).length;
|
|
292
|
+
const successRate = (successCount / iterations) * 100;
|
|
293
|
+
const averageDuration = results.reduce((sum, r) => sum + r.metrics.totalDuration, 0) / iterations;
|
|
294
|
+
const providerDistribution = {};
|
|
295
|
+
const tierDistribution = {};
|
|
296
|
+
results.forEach(result => {
|
|
297
|
+
if (result.selectedProvider) {
|
|
298
|
+
providerDistribution[result.selectedProvider] = (providerDistribution[result.selectedProvider] || 0) + 1;
|
|
299
|
+
}
|
|
300
|
+
if (result.selectedTier) {
|
|
301
|
+
tierDistribution[result.selectedTier] = (tierDistribution[result.selectedTier] || 0) + 1;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
const commonErrors = results
|
|
305
|
+
.flatMap(r => r.errors || [])
|
|
306
|
+
.map(e => e.message)
|
|
307
|
+
.reduce((acc, error) => {
|
|
308
|
+
acc[error] = (acc[error] || 0) + 1;
|
|
309
|
+
return acc;
|
|
310
|
+
}, {});
|
|
311
|
+
const sortedErrors = Object.entries(commonErrors)
|
|
312
|
+
.sort(([, a], [, b]) => b - a)
|
|
313
|
+
.slice(0, 5)
|
|
314
|
+
.map(([error]) => error);
|
|
315
|
+
return {
|
|
316
|
+
results,
|
|
317
|
+
summary: {
|
|
318
|
+
successRate,
|
|
319
|
+
averageDuration,
|
|
320
|
+
providerDistribution,
|
|
321
|
+
tierDistribution,
|
|
322
|
+
commonErrors: sortedErrors
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|