@hiper2d/ai-agents 0.5.2 → 0.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.
- package/dist/index.d.mts +42 -11
- package/dist/index.d.ts +42 -11
- package/dist/index.js +84 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -798,10 +798,8 @@ var LLM_CONSTANTS = {
|
|
|
798
798
|
GEMINI_PRO: "gemini-pro",
|
|
799
799
|
GEMINI_FLASH: "gemini-flash",
|
|
800
800
|
GEMINI_LITE: "gemini-lite",
|
|
801
|
-
MISTRAL_LARGE: "mistral-large",
|
|
802
801
|
MISTRAL_MEDIUM: "mistral-medium",
|
|
803
802
|
MISTRAL_SMALL: "mistral-small",
|
|
804
|
-
MISTRAL_MAGISTRAL: "mistral-magistral",
|
|
805
803
|
GROK: "grok",
|
|
806
804
|
KIMI: "kimi",
|
|
807
805
|
GLM: "glm",
|
|
@@ -959,36 +957,40 @@ var SupportedAiModels = {
|
|
|
959
957
|
hasThinking: true,
|
|
960
958
|
temperature: 0.7
|
|
961
959
|
},
|
|
962
|
-
// Mistral models
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
960
|
+
// Mistral models. Two hybrid entries since 2026-09-18: reasoning is off by default on the
|
|
961
|
+
// API and switched on per request with `reasoning_effort` (see mistral-agent.ts); the trace
|
|
962
|
+
// comes back as a `thinking` content chunk and works with json_schema structured output
|
|
963
|
+
// (verified live 2026-09-18 on both). Pinned to 'high' — the only level Mistral's docs
|
|
964
|
+
// describe ("full thinking chunk before the final answer"); Small is cheap enough that the
|
|
965
|
+
// extra tokens don't matter, Medium's are priced into its free-tier band via the hybrid
|
|
966
|
+
// multiplier. Live 2026-09-18 (one short schema ask each): Small 1.7s with a ~600-char
|
|
967
|
+
// trace, Medium 3.8s with ~2000 chars — Medium's trace ran ~15x its answer length.
|
|
968
|
+
//
|
|
969
|
+
// Mistral Large 3 and Magistral Medium 1.2 were dropped 2026-09-18. Large 3 was retired by
|
|
970
|
+
// Mistral on 2026-08-31 (the `-latest` alias still answered, but its capabilities say
|
|
971
|
+
// reasoning: false and `reasoning_effort` is a 400 on it). Magistral was retired 2026-07-31
|
|
972
|
+
// and `magistral-medium-latest` is now literally an alias of Medium 3.5 — the model list
|
|
973
|
+
// returns `mistral-medium-3-5`, `mistral-medium-3`, `mistral-medium-latest` and
|
|
974
|
+
// `magistral-medium-latest` as one entry — so Magistral seats had silently become Medium
|
|
975
|
+
// seats already. Consumers map both retired ids onto the surviving pair.
|
|
970
976
|
[LLM_CONSTANTS.MISTRAL_MEDIUM]: {
|
|
971
977
|
displayName: "Mistral Medium 3.5",
|
|
972
|
-
|
|
978
|
+
// The docs' explicit 3.5 id. It was `mistral-medium-3` until 2026-09-18, which Mistral
|
|
979
|
+
// now serves as an alias of the same model (Medium 3 itself retired 2026-08-31).
|
|
980
|
+
modelApiName: "mistral-medium-3-5",
|
|
973
981
|
apiKeyName: API_KEY_CONSTANTS.MISTRAL,
|
|
974
|
-
hasThinking:
|
|
975
|
-
|
|
982
|
+
hasThinking: true,
|
|
983
|
+
reasoningEffort: "high",
|
|
984
|
+
tags: ["fast", "expensive"]
|
|
976
985
|
},
|
|
977
986
|
[LLM_CONSTANTS.MISTRAL_SMALL]: {
|
|
978
987
|
displayName: "Mistral 4 Small",
|
|
988
|
+
// Resolves to mistral-small-2603 (Small 4), which also carries the magistral-small alias.
|
|
979
989
|
modelApiName: "mistral-small-latest",
|
|
980
990
|
apiKeyName: API_KEY_CONSTANTS.MISTRAL,
|
|
981
|
-
hasThinking: false,
|
|
982
|
-
tags: ["very-fast", "cheap"]
|
|
983
|
-
},
|
|
984
|
-
[LLM_CONSTANTS.MISTRAL_MAGISTRAL]: {
|
|
985
|
-
displayName: "Magistral Medium 1.2",
|
|
986
|
-
modelApiName: "magistral-medium-latest",
|
|
987
|
-
apiKeyName: API_KEY_CONSTANTS.MISTRAL,
|
|
988
991
|
hasThinking: true,
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
tags: ["very-fast"]
|
|
992
|
+
reasoningEffort: "high",
|
|
993
|
+
tags: ["very-fast", "cheap"]
|
|
992
994
|
},
|
|
993
995
|
// Kimi models. Single always-reasoning entry: K3 reasons by default and the only way to stop
|
|
994
996
|
// it is the undocumented K2-era `thinking: disabled` toggle, which we no longer rely on.
|
|
@@ -1316,13 +1318,10 @@ var MODEL_PRICING = {
|
|
|
1316
1318
|
outputPrice: 1.5,
|
|
1317
1319
|
cacheHitPrice: 0.025
|
|
1318
1320
|
},
|
|
1319
|
-
// Mistral models. Cached tokens bill at 10% of
|
|
1320
|
-
//
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
outputPrice: 1.5,
|
|
1324
|
-
cacheHitPrice: 0.05
|
|
1325
|
-
},
|
|
1321
|
+
// Mistral models (mistral.ai/pricing/api, verified 2026-09-18). Cached tokens bill at 10% of
|
|
1322
|
+
// the input price (documented on the prompt_cache_key param; no per-model cached prices
|
|
1323
|
+
// published). Reasoning tokens are counted inside completion_tokens — no separate
|
|
1324
|
+
// reasoning_tokens field — so the output rate already covers the trace.
|
|
1326
1325
|
[SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName]: {
|
|
1327
1326
|
inputPrice: 1.5,
|
|
1328
1327
|
outputPrice: 7.5,
|
|
@@ -1333,11 +1332,6 @@ var MODEL_PRICING = {
|
|
|
1333
1332
|
outputPrice: 0.6,
|
|
1334
1333
|
cacheHitPrice: 0.015
|
|
1335
1334
|
},
|
|
1336
|
-
[SupportedAiModels[LLM_CONSTANTS.MISTRAL_MAGISTRAL].modelApiName]: {
|
|
1337
|
-
inputPrice: 2,
|
|
1338
|
-
outputPrice: 5,
|
|
1339
|
-
cacheHitPrice: 0.2
|
|
1340
|
-
},
|
|
1341
1335
|
// Grok models. Cached price is per-model on xAI (not a uniform ratio):
|
|
1342
1336
|
// grok-4.6 is $0.50/M cached vs $2.00/M input, and all rates double for prompts
|
|
1343
1337
|
// >= 200K tokens, per docs.x.ai/developers/models (verified 2026-08-12).
|
|
@@ -1412,7 +1406,11 @@ var HYBRID_THINKING_API_NAMES = /* @__PURE__ */ new Set([
|
|
|
1412
1406
|
// hybrid by the same definition: we force reasoning on, so they carry the multiplier.
|
|
1413
1407
|
SupportedAiModels[LLM_CONSTANTS.QWEN_MAX].modelApiName,
|
|
1414
1408
|
SupportedAiModels[LLM_CONSTANTS.QWEN_FLASH].modelApiName,
|
|
1415
|
-
SupportedAiModels[LLM_CONSTANTS.MINIMAX].modelApiName
|
|
1409
|
+
SupportedAiModels[LLM_CONSTANTS.MINIMAX].modelApiName,
|
|
1410
|
+
// Mistral reasons only when asked (`reasoning_effort`), and we always ask — hybrid by the
|
|
1411
|
+
// same definition as Qwen. Added 2026-09-18 when the two entries went thinking-on.
|
|
1412
|
+
SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName,
|
|
1413
|
+
SupportedAiModels[LLM_CONSTANTS.MISTRAL_SMALL].modelApiName
|
|
1416
1414
|
]);
|
|
1417
1415
|
function isHybridThinkingModel(modelApiName) {
|
|
1418
1416
|
return HYBRID_THINKING_API_NAMES.has(modelApiName);
|
|
@@ -1476,6 +1474,7 @@ var GLM_REASONING_EFFORTS = ["low", "high", "max"];
|
|
|
1476
1474
|
var DEEPSEEK_REASONING_EFFORTS = ["low", "high", "max"];
|
|
1477
1475
|
var FUGU_REASONING_EFFORTS = ["high", "xhigh"];
|
|
1478
1476
|
var META_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh", "max"];
|
|
1477
|
+
var MISTRAL_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
|
|
1479
1478
|
function clampReasoningEffort(effort, allowed) {
|
|
1480
1479
|
const rank = REASONING_EFFORT_SCALE.indexOf(effort);
|
|
1481
1480
|
let best = allowed[0];
|
|
@@ -1496,6 +1495,7 @@ var toGlmEffort = (effort) => clampReasoningEffort(effort, GLM_REASONING_EFFORTS
|
|
|
1496
1495
|
var toDeepSeekEffort = (effort) => clampReasoningEffort(effort, DEEPSEEK_REASONING_EFFORTS);
|
|
1497
1496
|
var toMetaEffort = (effort) => clampReasoningEffort(effort, META_REASONING_EFFORTS);
|
|
1498
1497
|
var toFuguEffort = (effort) => clampReasoningEffort(effort, FUGU_REASONING_EFFORTS);
|
|
1498
|
+
var toMistralEffort = (effort) => clampReasoningEffort(effort, MISTRAL_REASONING_EFFORTS);
|
|
1499
1499
|
|
|
1500
1500
|
// src/pricing/token-usage-utils.ts
|
|
1501
1501
|
function extractTokenUsage(response) {
|
|
@@ -3228,6 +3228,9 @@ ${instruction}`);
|
|
|
3228
3228
|
const body = await request.clone().text();
|
|
3229
3229
|
const json = JSON.parse(body);
|
|
3230
3230
|
json.prompt_cache_key = promptCacheKey;
|
|
3231
|
+
if (this.enableThinking && this.reasoningEffort) {
|
|
3232
|
+
json.reasoning_effort = toMistralEffort(this.reasoningEffort);
|
|
3233
|
+
}
|
|
3231
3234
|
return new Request(request.url, {
|
|
3232
3235
|
method: request.method,
|
|
3233
3236
|
headers: request.headers,
|
|
@@ -3240,11 +3243,25 @@ ${instruction}`);
|
|
|
3240
3243
|
});
|
|
3241
3244
|
this.client = new Mistral({ apiKey, httpClient });
|
|
3242
3245
|
}
|
|
3246
|
+
/**
|
|
3247
|
+
* History in Mistral's shape. A prior assistant turn that carries a stored trace is
|
|
3248
|
+
* replayed as [thinking, text] chunks, as Mistral's multi-turn guidance asks; every other
|
|
3249
|
+
* turn is a plain string.
|
|
3250
|
+
*/
|
|
3243
3251
|
convertToMistralMessages(messages) {
|
|
3244
|
-
return this.prepareMessages(messages).map((msg) =>
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3252
|
+
return this.prepareMessages(messages).map((msg) => {
|
|
3253
|
+
if (msg.role === "assistant" && msg.thinking) {
|
|
3254
|
+
const chunks = [
|
|
3255
|
+
{ type: "thinking", thinking: [{ type: "text", text: msg.thinking }] },
|
|
3256
|
+
{ type: "text", text: msg.content }
|
|
3257
|
+
];
|
|
3258
|
+
return { role: "assistant", content: chunks };
|
|
3259
|
+
}
|
|
3260
|
+
return {
|
|
3261
|
+
role: msg.role === "developer" ? "system" : msg.role,
|
|
3262
|
+
content: msg.content
|
|
3263
|
+
};
|
|
3264
|
+
});
|
|
3248
3265
|
}
|
|
3249
3266
|
processReply(response) {
|
|
3250
3267
|
const message = response?.choices?.[0]?.message;
|
|
@@ -3279,7 +3296,6 @@ ${instruction}`);
|
|
|
3279
3296
|
extractTokenUsage(response) {
|
|
3280
3297
|
const usage = extractMistralTokenUsage(response);
|
|
3281
3298
|
if (!usage) return void 0;
|
|
3282
|
-
this.logger(`MISTRAL_CACHE_CALIBRATION raw usage: ${JSON.stringify(response?.usage)}`);
|
|
3283
3299
|
if (usage.reasoningTokens && usage.reasoningTokens > 0) {
|
|
3284
3300
|
this.logger(`\u{1F9E0} Reasoning tokens used: ${usage.reasoningTokens}`);
|
|
3285
3301
|
}
|
|
@@ -3315,7 +3331,7 @@ ${instruction}`);
|
|
|
3315
3331
|
const convertedMessages = this.convertToMistralMessages(messages);
|
|
3316
3332
|
if (convertedMessages.length > 0) {
|
|
3317
3333
|
const lastMessage = convertedMessages[convertedMessages.length - 1];
|
|
3318
|
-
if (lastMessage && lastMessage.content) {
|
|
3334
|
+
if (lastMessage && typeof lastMessage.content === "string" && lastMessage.content) {
|
|
3319
3335
|
lastMessage.content += `
|
|
3320
3336
|
|
|
3321
3337
|
Your response must be a valid JSON object matching this schema:
|
|
@@ -3386,9 +3402,8 @@ ${schemaDescription}`
|
|
|
3386
3402
|
}
|
|
3387
3403
|
}
|
|
3388
3404
|
/**
|
|
3389
|
-
* Plain-text ask: no schema appended, no responseFormat.
|
|
3390
|
-
*
|
|
3391
|
-
* json_object, so unlike askWithZodSchema this path can surface thinking content.
|
|
3405
|
+
* Plain-text ask: no schema appended, no responseFormat. Reasoning (and the trace) works
|
|
3406
|
+
* the same way as on the schema path.
|
|
3392
3407
|
*/
|
|
3393
3408
|
async doAskText(messages) {
|
|
3394
3409
|
try {
|
|
@@ -4412,6 +4427,18 @@ ${schemaDescription}`;
|
|
|
4412
4427
|
|
|
4413
4428
|
// src/agents/qwen-agent.ts
|
|
4414
4429
|
import { OpenAI as OpenAI9 } from "openai";
|
|
4430
|
+
function qwenRefusalFrom(model, apiError) {
|
|
4431
|
+
const message = apiError instanceof Error ? apiError.message : String(apiError);
|
|
4432
|
+
if (!/DataInspectionFailed|inappropriate content/i.test(message)) {
|
|
4433
|
+
return void 0;
|
|
4434
|
+
}
|
|
4435
|
+
const detail = message.replace(/^[\s\S]*DataInspectionFailed:\s*/, "").trim();
|
|
4436
|
+
return new ModelRefusalError(
|
|
4437
|
+
model,
|
|
4438
|
+
`${model} refused the prompt (refusalReason: DataInspectionFailed${detail ? `; ${detail}` : ""})`,
|
|
4439
|
+
"DataInspectionFailed"
|
|
4440
|
+
);
|
|
4441
|
+
}
|
|
4415
4442
|
var QwenAgent = class extends AbstractAgent {
|
|
4416
4443
|
client;
|
|
4417
4444
|
// A getter, not a field: `maxOutputTokens` can be raised after construction, and a field
|
|
@@ -4536,7 +4563,7 @@ ${schemaDescription}`;
|
|
|
4536
4563
|
completion = await this.client.chat.completions.create(params);
|
|
4537
4564
|
} catch (apiError) {
|
|
4538
4565
|
this.logger(this.logTemplates.error(this.name, apiError));
|
|
4539
|
-
throw new Error(this.errorMessages.apiError(apiError));
|
|
4566
|
+
throw qwenRefusalFrom(this.model, apiError) ?? new Error(this.errorMessages.apiError(apiError));
|
|
4540
4567
|
}
|
|
4541
4568
|
const rawReply = completion.choices[0]?.message?.content;
|
|
4542
4569
|
if (!rawReply) {
|
|
@@ -4556,6 +4583,9 @@ ${schemaDescription}`;
|
|
|
4556
4583
|
return [validated, thinkingContent, tokenUsage];
|
|
4557
4584
|
} catch (error) {
|
|
4558
4585
|
this.logger(this.logTemplates.error(this.name, error));
|
|
4586
|
+
if (error instanceof ModelError) {
|
|
4587
|
+
throw error;
|
|
4588
|
+
}
|
|
4559
4589
|
throw new Error(this.errorMessages.apiError(error));
|
|
4560
4590
|
}
|
|
4561
4591
|
}
|
|
@@ -4589,7 +4619,7 @@ ${openAIMessages[0].content}`;
|
|
|
4589
4619
|
completion = await this.client.chat.completions.create(params);
|
|
4590
4620
|
} catch (apiError) {
|
|
4591
4621
|
this.logger(this.logTemplates.error(this.name, apiError));
|
|
4592
|
-
throw new Error(this.errorMessages.apiError(apiError));
|
|
4622
|
+
throw qwenRefusalFrom(this.model, apiError) ?? new Error(this.errorMessages.apiError(apiError));
|
|
4593
4623
|
}
|
|
4594
4624
|
const rawReply = completion.choices[0]?.message?.content;
|
|
4595
4625
|
if (!rawReply) {
|
|
@@ -4605,6 +4635,9 @@ ${openAIMessages[0].content}`;
|
|
|
4605
4635
|
return [reply, thinkingContent, tokenUsage];
|
|
4606
4636
|
} catch (error) {
|
|
4607
4637
|
this.logger(this.logTemplates.error(this.name, error));
|
|
4638
|
+
if (error instanceof ModelError) {
|
|
4639
|
+
throw error;
|
|
4640
|
+
}
|
|
4608
4641
|
throw new Error(this.errorMessages.apiError(error));
|
|
4609
4642
|
}
|
|
4610
4643
|
}
|
|
@@ -5042,8 +5075,6 @@ var AgentFactory = class {
|
|
|
5042
5075
|
// Mistral models
|
|
5043
5076
|
case LLM_CONSTANTS.MISTRAL_MEDIUM:
|
|
5044
5077
|
case LLM_CONSTANTS.MISTRAL_SMALL:
|
|
5045
|
-
case LLM_CONSTANTS.MISTRAL_LARGE:
|
|
5046
|
-
case LLM_CONSTANTS.MISTRAL_MAGISTRAL:
|
|
5047
5078
|
return new MistralAgent(name, instruction, model.modelApiName, key, shouldEnableThinking);
|
|
5048
5079
|
case LLM_CONSTANTS.KIMI:
|
|
5049
5080
|
return new KimiAgent(name, instruction, model.modelApiName, key, 0, shouldEnableThinking);
|
|
@@ -5106,6 +5137,7 @@ export {
|
|
|
5106
5137
|
LLM_CONSTANTS,
|
|
5107
5138
|
MESSAGE_ROLE,
|
|
5108
5139
|
META_REASONING_EFFORTS,
|
|
5140
|
+
MISTRAL_REASONING_EFFORTS,
|
|
5109
5141
|
MODEL_PRICING,
|
|
5110
5142
|
MetaAgent,
|
|
5111
5143
|
MiniMaxAgent,
|
|
@@ -5207,6 +5239,7 @@ export {
|
|
|
5207
5239
|
toGeminiEffort,
|
|
5208
5240
|
toGlmEffort,
|
|
5209
5241
|
toMetaEffort,
|
|
5242
|
+
toMistralEffort,
|
|
5210
5243
|
toOpenAIEffort,
|
|
5211
5244
|
transcribeWithGemini,
|
|
5212
5245
|
transcribeWithOpenAi,
|