modelmix 5.1.19 → 5.2.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/.gitignore +138 -0
- package/README.md +45 -3
- package/demo/benchmark.js +83 -0
- package/demo/package.json +2 -0
- package/demo/prompts/story.txt +35 -0
- package/demo/prompts/template-engine.txt +41 -0
- package/demo/short.js +3 -0
- package/effort.js +4 -1
- package/index.d.ts +9 -0
- package/index.js +33 -5
- package/lib/model-chain.js +2 -2
- package/lib/parse-json-response.js +14 -0
- package/lib/providers/anthropic.js +3 -1
- package/lib/providers/base.js +65 -17
- package/lib/providers/google.js +13 -2
- package/lib/providers/openai-compatible.js +36 -0
- package/lib/providers/openai-options.js +1 -1
- package/lib/providers/openai.js +5 -1
- package/lib/token-usage.js +10 -4
- package/package.json +5 -5
- package/plugins/benchmark/index.d.ts +112 -0
- package/plugins/benchmark/index.js +575 -0
- package/plugins/benchmark/test/benchmark.test.js +518 -0
- package/skills/modelmix/SKILL.md +14 -5
- package/test/deepseek.test.js +273 -1
- package/test/effort.test.js +9 -0
- package/test/fallback.test.js +97 -5
- package/test/google.test.js +55 -0
- package/test/history.test.js +7 -4
- package/test/json.test.js +29 -1
- package/test/public-api.test.js +2 -0
- package/test/tokens.test.js +83 -3
- package/RLM_PLUGIN_SPEC.md +0 -465
- package/demo/package-lock.json +0 -516
|
@@ -278,9 +278,11 @@ function createAnthropicProviders({ ModelMix, MixCustom, log }) {
|
|
|
278
278
|
);
|
|
279
279
|
const input = (data.usage.input_tokens || 0) + cached + cacheWrite;
|
|
280
280
|
const output = data.usage.output_tokens || 0;
|
|
281
|
+
const thinking = data.usage.output_tokens_details?.thinking_tokens || 0;
|
|
281
282
|
return ModelMix.normalizeTokenUsage({
|
|
282
283
|
input,
|
|
283
|
-
output,
|
|
284
|
+
output: output - thinking,
|
|
285
|
+
thinking,
|
|
284
286
|
total: input + output,
|
|
285
287
|
cached,
|
|
286
288
|
cacheWrite,
|
package/lib/providers/base.js
CHANGED
|
@@ -146,6 +146,10 @@ function createBaseProviders({ ModelMix }) {
|
|
|
146
146
|
let raw = [];
|
|
147
147
|
let message = '';
|
|
148
148
|
let buffer = '';
|
|
149
|
+
let completed = false;
|
|
150
|
+
let chatCompletion = false;
|
|
151
|
+
let usage = {};
|
|
152
|
+
let usageMetadata;
|
|
149
153
|
|
|
150
154
|
response.data.on('data', chunk => {
|
|
151
155
|
buffer += chunk.toString();
|
|
@@ -156,39 +160,75 @@ function createBaseProviders({ ModelMix }) {
|
|
|
156
160
|
buffer = buffer.slice(boundary + 1);
|
|
157
161
|
|
|
158
162
|
const firstBraceIndex = dataStr.indexOf('{');
|
|
159
|
-
if (dataStr === '[DONE]' ||
|
|
163
|
+
if (dataStr === 'data: [DONE]' || dataStr === '[DONE]') {
|
|
164
|
+
completed = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (firstBraceIndex === -1) continue;
|
|
160
168
|
|
|
161
169
|
const jsonStr = dataStr.slice(firstBraceIndex);
|
|
162
170
|
try {
|
|
163
171
|
const data = JSON.parse(jsonStr);
|
|
172
|
+
MixCustom.assertResponse(data);
|
|
173
|
+
chatCompletion ||= Array.isArray(data.choices);
|
|
174
|
+
completed ||= Boolean(data.choices?.[0]?.finish_reason);
|
|
175
|
+
raw.push(data);
|
|
176
|
+
usage = { ...usage, ...data.message?.usage, ...data.usage };
|
|
177
|
+
if (data.usageMetadata) usageMetadata = data.usageMetadata;
|
|
178
|
+
const delta = this.extractDelta(data);
|
|
179
|
+
message += delta;
|
|
164
180
|
if (this.streamCallback) {
|
|
165
|
-
const delta = this.extractDelta(data);
|
|
166
|
-
message += delta;
|
|
167
181
|
this.streamCallback({ response: data, message, delta });
|
|
168
|
-
raw.push(data);
|
|
169
182
|
}
|
|
170
183
|
} catch (error) {
|
|
171
|
-
|
|
184
|
+
reject(error);
|
|
185
|
+
response.data.destroy();
|
|
186
|
+
return;
|
|
172
187
|
}
|
|
173
188
|
}
|
|
174
189
|
});
|
|
175
190
|
|
|
176
|
-
response.data.on('end', () =>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
response.data.on('end', () => {
|
|
192
|
+
if (chatCompletion && !completed) {
|
|
193
|
+
reject(MixCustom.responseError(raw.at(-1), 'Provider stream ended without completing.'));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
resolve({
|
|
197
|
+
response: raw,
|
|
198
|
+
message: message.trim(),
|
|
199
|
+
toolCalls: [],
|
|
200
|
+
think: null,
|
|
201
|
+
tokens: this.constructor.extractTokens({ usage, usageMetadata })
|
|
202
|
+
});
|
|
203
|
+
});
|
|
183
204
|
response.data.on('error', reject);
|
|
184
205
|
});
|
|
185
206
|
}
|
|
186
207
|
|
|
187
208
|
extractDelta(data) {
|
|
188
|
-
return data.choices[0]
|
|
209
|
+
return data.choices?.[0]?.delta?.content || '';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static responseError(data, message, statusCode = 502) {
|
|
213
|
+
const error = new Error(message);
|
|
214
|
+
error.statusCode = statusCode;
|
|
215
|
+
error.details = data;
|
|
216
|
+
return error;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static assertResponse(data) {
|
|
220
|
+
const failure = data?.error || data?.choices?.find(choice => choice.error)?.error;
|
|
221
|
+
if (failure || data?.choices?.some(choice => choice.finish_reason === 'error') || data?.status === 'failed') {
|
|
222
|
+
throw MixCustom.responseError(
|
|
223
|
+
data,
|
|
224
|
+
failure?.message || 'Provider failed to complete the response.',
|
|
225
|
+
Number.isInteger(failure?.code) && failure.code >= 400 && failure.code <= 599 ? failure.code : 502
|
|
226
|
+
);
|
|
227
|
+
}
|
|
189
228
|
}
|
|
190
229
|
|
|
191
230
|
static extractMessage(data) {
|
|
231
|
+
MixCustom.assertResponse(data);
|
|
192
232
|
const choice = data?.choices?.[0] || {};
|
|
193
233
|
const messageObj = choice.message || {};
|
|
194
234
|
const finishReason = choice.finish_reason;
|
|
@@ -254,9 +294,12 @@ function createBaseProviders({ ModelMix }) {
|
|
|
254
294
|
static extractTokens(data) {
|
|
255
295
|
// OpenAI/Groq/Together/Lambda/Cerebras/Fireworks format
|
|
256
296
|
if (data.usage) {
|
|
297
|
+
const output = data.usage.completion_tokens || 0;
|
|
298
|
+
const thinking = data.usage.completion_tokens_details?.reasoning_tokens || 0;
|
|
257
299
|
return ModelMix.normalizeTokenUsage({
|
|
258
300
|
input: data.usage.prompt_tokens || 0,
|
|
259
|
-
output:
|
|
301
|
+
output: output - thinking,
|
|
302
|
+
thinking,
|
|
260
303
|
total: data.usage.total_tokens,
|
|
261
304
|
cached: ModelMix.extractCacheTokens(data.usage),
|
|
262
305
|
cacheWrite: ModelMix.extractCacheWriteTokens(data.usage)
|
|
@@ -266,11 +309,16 @@ function createBaseProviders({ ModelMix }) {
|
|
|
266
309
|
}
|
|
267
310
|
|
|
268
311
|
processResponse(response) {
|
|
312
|
+
const message = MixCustom.extractMessage(response.data);
|
|
313
|
+
const toolCalls = MixCustom.extractToolCalls(response.data);
|
|
314
|
+
if (!message && toolCalls.length === 0 && response.data?.choices?.[0]?.finish_reason !== 'length') {
|
|
315
|
+
throw MixCustom.responseError(response.data, 'Provider returned no text or tool calls without completing a usable response.');
|
|
316
|
+
}
|
|
269
317
|
return {
|
|
270
|
-
message
|
|
318
|
+
message,
|
|
271
319
|
think: MixCustom.extractThink(response.data),
|
|
272
|
-
toolCalls
|
|
273
|
-
tokens:
|
|
320
|
+
toolCalls,
|
|
321
|
+
tokens: this.constructor.extractTokens(response.data),
|
|
274
322
|
response: response.data
|
|
275
323
|
}
|
|
276
324
|
}
|
package/lib/providers/google.js
CHANGED
|
@@ -61,6 +61,12 @@ function createGoogleProviders({ ModelMix, MixCustom }) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
if (typeof message.content === 'string') {
|
|
65
|
+
return {
|
|
66
|
+
role: message.role === 'assistant' ? 'model' : 'user',
|
|
67
|
+
parts: [{ text: message.content }]
|
|
68
|
+
};
|
|
69
|
+
}
|
|
64
70
|
if (!Array.isArray(message.content)) return message;
|
|
65
71
|
const role = (message.role === 'assistant' || message.role === 'tool') ? 'model' : 'user'
|
|
66
72
|
|
|
@@ -164,7 +170,10 @@ function createGoogleProviders({ ModelMix, MixCustom }) {
|
|
|
164
170
|
options.tools.some(t => t.functionDeclarations && t.functionDeclarations.length > 0);
|
|
165
171
|
|
|
166
172
|
if (!hasTools) {
|
|
167
|
-
generationConfig.responseMimeType =
|
|
173
|
+
generationConfig.responseMimeType = options.response_format?.type === 'json_object'
|
|
174
|
+
|| options.response_format?.type === 'json_schema'
|
|
175
|
+
? 'application/json'
|
|
176
|
+
: 'text/plain';
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
const payload = {
|
|
@@ -230,7 +239,9 @@ function createGoogleProviders({ ModelMix, MixCustom }) {
|
|
|
230
239
|
}
|
|
231
240
|
|
|
232
241
|
static extractMessage(data) {
|
|
233
|
-
|
|
242
|
+
const parts = data.candidates?.[0]?.content?.parts;
|
|
243
|
+
const textParts = parts?.filter(part => !part.thought && typeof part.text === 'string');
|
|
244
|
+
return textParts?.length ? textParts.map(part => part.text).join('') : undefined;
|
|
234
245
|
}
|
|
235
246
|
|
|
236
247
|
static extractTokens(data) {
|
|
@@ -5,6 +5,29 @@ const {
|
|
|
5
5
|
const { requireProviderApiKey } = require('../provider-api-key');
|
|
6
6
|
|
|
7
7
|
function createCompatibleProviders({ MixCustom, MixOpenAI }) {
|
|
8
|
+
class MixDeepSeek extends MixOpenAI {
|
|
9
|
+
getDefaultConfig(customConfig) {
|
|
10
|
+
const apiKey = requireProviderApiKey(customConfig, 'DEEPSEEK_API_KEY', 'DeepSeek');
|
|
11
|
+
|
|
12
|
+
return MixCustom.prototype.getDefaultConfig.call(this, {
|
|
13
|
+
url: 'https://api.deepseek.com/chat/completions',
|
|
14
|
+
apiKey,
|
|
15
|
+
...customConfig
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
extractDelta(data) {
|
|
20
|
+
return data?.choices?.[0]?.delta?.content || '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
processResponse(response) {
|
|
24
|
+
return {
|
|
25
|
+
...super.processResponse(response),
|
|
26
|
+
assistantMessage: response.data?.choices?.[0]?.message
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
8
31
|
class MixMiniMax extends MixOpenAI {
|
|
9
32
|
getDefaultConfig(customConfig) {
|
|
10
33
|
const apiKey = requireProviderApiKey(customConfig, 'MINIMAX_API_KEY', 'MiniMax');
|
|
@@ -124,6 +147,18 @@ function createCompatibleProviders({ MixCustom, MixOpenAI }) {
|
|
|
124
147
|
}
|
|
125
148
|
|
|
126
149
|
class MixGrok extends MixOpenAI {
|
|
150
|
+
static extractTokens(data) {
|
|
151
|
+
if (!data.usage) return MixCustom.extractTokens(data);
|
|
152
|
+
return MixCustom.extractTokens({
|
|
153
|
+
...data,
|
|
154
|
+
usage: {
|
|
155
|
+
...data.usage,
|
|
156
|
+
completion_tokens: (data.usage.completion_tokens || 0)
|
|
157
|
+
+ (data.usage.completion_tokens_details?.reasoning_tokens || 0)
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
127
162
|
getDefaultConfig(customConfig) {
|
|
128
163
|
const apiKey = requireProviderApiKey(customConfig, 'XAI_API_KEY', 'Grok');
|
|
129
164
|
|
|
@@ -292,6 +327,7 @@ function createCompatibleProviders({ MixCustom, MixOpenAI }) {
|
|
|
292
327
|
}
|
|
293
328
|
|
|
294
329
|
return {
|
|
330
|
+
MixDeepSeek,
|
|
295
331
|
MixMiniMax,
|
|
296
332
|
MixMiMo,
|
|
297
333
|
MixPerplexity,
|
|
@@ -3,7 +3,7 @@ function normalizeOpenAIOptions(options) {
|
|
|
3
3
|
delete options.max_tokens;
|
|
4
4
|
delete options.temperature;
|
|
5
5
|
}
|
|
6
|
-
if (options.model?.includes('gpt-5')) {
|
|
6
|
+
if (options.model?.includes('gpt-5') || /^(?:openai\/)?gpt-6-astra(?:-|$)/.test(options.model || '')) {
|
|
7
7
|
if (options.max_tokens) {
|
|
8
8
|
options.max_completion_tokens = options.max_tokens;
|
|
9
9
|
delete options.max_tokens;
|
package/lib/providers/openai.js
CHANGED
|
@@ -136,6 +136,7 @@ function createOpenAIProviders({
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
static processResponsesResponse(response) {
|
|
139
|
+
MixCustom.assertResponse(response.data);
|
|
139
140
|
const message = MixOpenAIResponses.extractResponsesMessage(response.data);
|
|
140
141
|
return {
|
|
141
142
|
message,
|
|
@@ -148,9 +149,12 @@ function createOpenAIProviders({
|
|
|
148
149
|
|
|
149
150
|
static extractResponsesTokens(data) {
|
|
150
151
|
if (data.usage) {
|
|
152
|
+
const output = data.usage.output_tokens || 0;
|
|
153
|
+
const thinking = data.usage.output_tokens_details?.reasoning_tokens || 0;
|
|
151
154
|
return ModelMix.normalizeTokenUsage({
|
|
152
155
|
input: data.usage.input_tokens || 0,
|
|
153
|
-
output:
|
|
156
|
+
output: output - thinking,
|
|
157
|
+
thinking,
|
|
154
158
|
total: data.usage.total_tokens,
|
|
155
159
|
cached: ModelMix.extractCacheTokens(data.usage),
|
|
156
160
|
cacheWrite: ModelMix.extractCacheWriteTokens(data.usage)
|
package/lib/token-usage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const OPENAI_LONG_CONTEXT_PRICING = Object.freeze({
|
|
2
2
|
inputThreshold: 272_000,
|
|
3
3
|
inputMultiplier: 2,
|
|
4
4
|
outputMultiplier: 1.5
|
|
@@ -21,11 +21,12 @@ function usesLongContextRates(pricing, inputTokens) {
|
|
|
21
21
|
|
|
22
22
|
const MODEL_PRICING = {
|
|
23
23
|
// OpenAI
|
|
24
|
+
'gpt-6-astra': { input: 10.00, cachedInput: 1.00, cacheWrite: 12.50, output: 50.00, longContext: OPENAI_LONG_CONTEXT_PRICING },
|
|
24
25
|
'gpt-realtime-mini': { input: 0.60, cachedInput: 0.06, output: 2.40 },
|
|
25
26
|
'gpt-realtime': { input: 4.00, cachedInput: 0.40, output: 16.00 },
|
|
26
|
-
'gpt-5.6-sol': { input: 5.00, cachedInput: 0.50, cacheWrite: 6.25, output: 30.00, longContext:
|
|
27
|
-
'gpt-5.6-terra': { input: 2.00, cachedInput: 0.20, cacheWrite: 2.50, output: 12.00, longContext:
|
|
28
|
-
'gpt-5.6-luna': { input: 0.20, cachedInput: 0.02, cacheWrite: 0.25, output: 1.20, longContext:
|
|
27
|
+
'gpt-5.6-sol': { input: 5.00, cachedInput: 0.50, cacheWrite: 6.25, output: 30.00, longContext: OPENAI_LONG_CONTEXT_PRICING },
|
|
28
|
+
'gpt-5.6-terra': { input: 2.00, cachedInput: 0.20, cacheWrite: 2.50, output: 12.00, longContext: OPENAI_LONG_CONTEXT_PRICING },
|
|
29
|
+
'gpt-5.6-luna': { input: 0.20, cachedInput: 0.02, cacheWrite: 0.25, output: 1.20, longContext: OPENAI_LONG_CONTEXT_PRICING },
|
|
29
30
|
'gpt-5.5-pro': { input: 30.00, output: 180.00 },
|
|
30
31
|
'gpt-5.5': { input: 5.00, cachedInput: 0.50, output: 30.00 },
|
|
31
32
|
'gpt-5.4': { input: 2.50, cachedInput: 0.25, output: 15.00 },
|
|
@@ -95,6 +96,10 @@ const MODEL_PRICING = {
|
|
|
95
96
|
'deepseek-ai/DeepSeek-V4-Flash': { input: 0.14, output: 0.28 },
|
|
96
97
|
'deepseek-ai/DeepSeek-V4-Pro': { input: 2.10, output: 4.40 },
|
|
97
98
|
'deepseek/deepseek-v4-flash': { input: 0.09, output: 0.18 },
|
|
99
|
+
'deepseek/deepseek-v4.1-flash': { input: 0.15, cachedInput: 0.015, output: 0.60 },
|
|
100
|
+
'accounts/fireworks/models/deepseek-v4p1-flash': { input: 0.22, cachedInput: 0.007, output: 0.66 },
|
|
101
|
+
'deepseek-flash': { input: 0.30, cachedInput: 0.006, output: 1.20 },
|
|
102
|
+
'deepseek/deepseek-v4-pro-0813': { input: 0.5808, cachedInput: 0.05808, output: 1.7424 },
|
|
98
103
|
'accounts/fireworks/models/glm-4p7': { input: 0.55, output: 2.19 },
|
|
99
104
|
'zai-org/GLM-5.2': { input: 1.40, cachedInput: 0.26, output: 4.40 },
|
|
100
105
|
'accounts/fireworks/models/glm-5p2': { input: 1.40, cachedInput: 0.14, output: 4.40 },
|
|
@@ -321,6 +326,7 @@ function getModelPricing(modelKey) {
|
|
|
321
326
|
function extractCacheTokens(usage = {}) {
|
|
322
327
|
return usage.input_tokens_details?.cached_tokens
|
|
323
328
|
?? usage.prompt_tokens_details?.cached_tokens
|
|
329
|
+
?? usage.prompt_cache_hit_tokens
|
|
324
330
|
?? usage.cache_read_input_tokens
|
|
325
331
|
?? usage.cachedContentTokenCount
|
|
326
332
|
?? usage.cached_content_token_count
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelmix",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "🧬 Reliable interface with automatic fallback for AI LLMs.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
"test:live.mcp": "mocha test/live.mcp.js --timeout 60000 --require test/setup.js",
|
|
78
78
|
"test:tokens": "mocha test/tokens.test.js --timeout 10000 --require test/setup.js",
|
|
79
79
|
"test:plugins": "mocha test/plugins.test.js --timeout 10000 --require test/setup.js",
|
|
80
|
+
"test:benchmark": "mocha plugins/benchmark/test/**/*.test.js --timeout 10000 --require test/setup.js",
|
|
80
81
|
"test:rlm": "mocha plugins/rlm/test/**/*.test.js --timeout 10000 --require test/setup.js",
|
|
81
|
-
"test:offline": "mocha test/abort.test.js test/json.test.js test/fallback.test.js test/templates.test.js test/images.test.js test/bottleneck.test.js test/tokens.test.js test/history.test.js test/anthropic.test.js test/effort.test.js test/grok.test.js test/moderation.test.js test/plugins.test.js plugins/rlm/test/**/*.test.js --timeout 10000 --require test/setup.js"
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
}
|
|
82
|
+
"test:offline": "mocha test/abort.test.js test/json.test.js test/fallback.test.js test/templates.test.js test/images.test.js test/bottleneck.test.js test/tokens.test.js test/history.test.js test/anthropic.test.js test/effort.test.js test/grok.test.js test/google.test.js test/moderation.test.js test/plugins.test.js plugins/benchmark/test/**/*.test.js plugins/rlm/test/**/*.test.js --timeout 10000 --require test/setup.js"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { ChatMessage, ModelMixMixFlags, ModelMixPlugin, TokenUsage } from '../..';
|
|
2
|
+
|
|
3
|
+
export interface BenchmarkOptions {
|
|
4
|
+
criteriaModel: string;
|
|
5
|
+
models: string[];
|
|
6
|
+
mix?: ModelMixMixFlags;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface BenchmarkModel {
|
|
10
|
+
id: string;
|
|
11
|
+
shortcut: string;
|
|
12
|
+
effort: number | null;
|
|
13
|
+
canonicalModel: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BenchmarkCriterion {
|
|
17
|
+
id: string;
|
|
18
|
+
description: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BenchmarkScore {
|
|
22
|
+
criterionId: string;
|
|
23
|
+
score: number;
|
|
24
|
+
justification: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BenchmarkCallMetrics {
|
|
28
|
+
elapsedMs: number;
|
|
29
|
+
tokens: Partial<TokenUsage> | null;
|
|
30
|
+
cost: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface BenchmarkEvaluation {
|
|
34
|
+
judge: BenchmarkModel;
|
|
35
|
+
scores: BenchmarkScore[];
|
|
36
|
+
metrics: BenchmarkCallMetrics;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface BenchmarkCriterionAverage {
|
|
40
|
+
criterionId: string;
|
|
41
|
+
score: number | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface BenchmarkResult {
|
|
45
|
+
id: string;
|
|
46
|
+
shortcut: string;
|
|
47
|
+
effort: number | null;
|
|
48
|
+
canonicalModel: string;
|
|
49
|
+
response: string | null;
|
|
50
|
+
responseMetrics: BenchmarkCallMetrics | null;
|
|
51
|
+
evaluations: BenchmarkEvaluation[];
|
|
52
|
+
averages: BenchmarkCriterionAverage[] | null;
|
|
53
|
+
score: number | null;
|
|
54
|
+
evaluationCount: {
|
|
55
|
+
expected: number;
|
|
56
|
+
valid: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface BenchmarkErrorDetails {
|
|
61
|
+
name: string;
|
|
62
|
+
message: string;
|
|
63
|
+
code?: unknown;
|
|
64
|
+
statusCode?: unknown;
|
|
65
|
+
details?: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface BenchmarkError {
|
|
69
|
+
stage: 'response' | 'evaluation';
|
|
70
|
+
participant: string;
|
|
71
|
+
judge?: string;
|
|
72
|
+
error: BenchmarkErrorDetails;
|
|
73
|
+
metrics: BenchmarkCallMetrics;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface BenchmarkTokenTotals {
|
|
77
|
+
input?: number;
|
|
78
|
+
output?: number;
|
|
79
|
+
thinking?: number;
|
|
80
|
+
total?: number;
|
|
81
|
+
cached?: number;
|
|
82
|
+
cacheWrite?: number;
|
|
83
|
+
cacheWrite5m?: number;
|
|
84
|
+
cacheWrite1h?: number;
|
|
85
|
+
uncachedInput?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface BenchmarkReport {
|
|
89
|
+
task: {
|
|
90
|
+
system: string;
|
|
91
|
+
messages: ChatMessage[];
|
|
92
|
+
};
|
|
93
|
+
criteria: {
|
|
94
|
+
model: BenchmarkModel;
|
|
95
|
+
items: BenchmarkCriterion[];
|
|
96
|
+
metrics: BenchmarkCallMetrics;
|
|
97
|
+
};
|
|
98
|
+
results: BenchmarkResult[];
|
|
99
|
+
errors: BenchmarkError[];
|
|
100
|
+
metrics: {
|
|
101
|
+
elapsedMs: number;
|
|
102
|
+
tokens: BenchmarkTokenTotals | null;
|
|
103
|
+
cost: number | null;
|
|
104
|
+
calls: {
|
|
105
|
+
attempted: number;
|
|
106
|
+
withTokens: number;
|
|
107
|
+
withCost: number;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export declare function benchmark(options: BenchmarkOptions): ModelMixPlugin;
|