@core-ai/mistral 0.15.0 → 0.17.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.js +216 -42
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
// src/chat-adapter.ts
|
|
14
14
|
import {
|
|
15
15
|
asObject,
|
|
16
|
+
getProviderMetadata,
|
|
16
17
|
safeParseJsonObject,
|
|
17
18
|
zodSchemaToJsonSchema
|
|
18
19
|
} from "@core-ai/core-ai";
|
|
@@ -49,13 +50,31 @@ function parseMistralEmbedProviderOptions(providerOptions) {
|
|
|
49
50
|
}
|
|
50
51
|
var mistralProviderOptionsSchema = mistralGenerateProviderOptionsSchema;
|
|
51
52
|
|
|
53
|
+
// src/model-capabilities.ts
|
|
54
|
+
var NO_REASONING_CAPABILITIES = {
|
|
55
|
+
reasoning: {
|
|
56
|
+
mode: "unsupported",
|
|
57
|
+
supportedEfforts: [],
|
|
58
|
+
restrictsSamplingParams: false,
|
|
59
|
+
supportedToolChoices: ["auto", "none", "required", "tool"]
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function getMistralModelCapabilities(_modelId) {
|
|
63
|
+
return NO_REASONING_CAPABILITIES;
|
|
64
|
+
}
|
|
65
|
+
|
|
52
66
|
// src/chat-adapter.ts
|
|
67
|
+
var MISTRAL_REASONING_METADATA_NAMESPACE = "mistral";
|
|
53
68
|
var DEFAULT_STRUCTURED_OUTPUT_TOOL_NAME = "core_ai_generate_object";
|
|
54
69
|
var DEFAULT_STRUCTURED_OUTPUT_TOOL_DESCRIPTION = "Return a JSON object that matches the requested schema.";
|
|
55
|
-
function convertMessages(messages) {
|
|
56
|
-
|
|
70
|
+
function convertMessages(messages, options = {}) {
|
|
71
|
+
const includeReasoning = options.includeReasoning ?? true;
|
|
72
|
+
return messages.flatMap((message) => {
|
|
73
|
+
const convertedMessage = convertMessage(message, includeReasoning);
|
|
74
|
+
return convertedMessage ? [convertedMessage] : [];
|
|
75
|
+
});
|
|
57
76
|
}
|
|
58
|
-
function convertMessage(message) {
|
|
77
|
+
function convertMessage(message, includeReasoning) {
|
|
59
78
|
if (message.role === "system") {
|
|
60
79
|
return {
|
|
61
80
|
role: "system",
|
|
@@ -77,12 +96,26 @@ function convertMessage(message) {
|
|
|
77
96
|
if (part.type === "text") {
|
|
78
97
|
contentChunks.push({ type: "text", text: part.text });
|
|
79
98
|
} else if (part.type === "reasoning" && part.text.length > 0) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
const isNativeMistralReasoning = getProviderMetadata(
|
|
100
|
+
part.providerMetadata,
|
|
101
|
+
MISTRAL_REASONING_METADATA_NAMESPACE
|
|
102
|
+
) != null;
|
|
103
|
+
if (includeReasoning && isNativeMistralReasoning) {
|
|
104
|
+
contentChunks.push({
|
|
105
|
+
type: "thinking",
|
|
106
|
+
thinking: [{ type: "text", text: part.text }]
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
contentChunks.push({
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `<thinking>${part.text}</thinking>`
|
|
112
|
+
});
|
|
113
|
+
}
|
|
84
114
|
}
|
|
85
115
|
}
|
|
116
|
+
if (contentChunks.length === 0 && toolCalls.length === 0) {
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
86
119
|
return {
|
|
87
120
|
role: "assistant",
|
|
88
121
|
content: contentChunks.length > 0 ? contentChunks : null,
|
|
@@ -127,14 +160,16 @@ function convertUserContentPart(part) {
|
|
|
127
160
|
};
|
|
128
161
|
}
|
|
129
162
|
function convertTools(tools) {
|
|
130
|
-
return Object.values(tools).map(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
163
|
+
return Object.values(tools).map(
|
|
164
|
+
(tool) => ({
|
|
165
|
+
type: "function",
|
|
166
|
+
function: {
|
|
167
|
+
name: tool.name,
|
|
168
|
+
description: tool.description,
|
|
169
|
+
parameters: zodSchemaToJsonSchema(tool.parameters)
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
);
|
|
138
173
|
}
|
|
139
174
|
function convertToolChoice(choice) {
|
|
140
175
|
if (typeof choice === "string") {
|
|
@@ -193,9 +228,12 @@ function createStreamRequest(modelId, options) {
|
|
|
193
228
|
return mapMistralProviderOptionsToRequest(baseRequest, mistralOptions);
|
|
194
229
|
}
|
|
195
230
|
function createRequestBase(modelId, options) {
|
|
231
|
+
const capabilities = getMistralModelCapabilities(modelId);
|
|
196
232
|
return {
|
|
197
233
|
model: modelId,
|
|
198
|
-
messages: convertMessages(options.messages
|
|
234
|
+
messages: convertMessages(options.messages, {
|
|
235
|
+
includeReasoning: capabilities.reasoning.mode !== "unsupported"
|
|
236
|
+
}),
|
|
199
237
|
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
200
238
|
...options.toolChoice ? { toolChoice: convertToolChoice(options.toolChoice) } : {},
|
|
201
239
|
...mapSamplingToRequestFields(options)
|
|
@@ -235,6 +273,16 @@ function mapGenerateResponse(response) {
|
|
|
235
273
|
usage: mapUsage(response.usage)
|
|
236
274
|
};
|
|
237
275
|
}
|
|
276
|
+
if (!firstChoice.message) {
|
|
277
|
+
return {
|
|
278
|
+
parts: [],
|
|
279
|
+
content: null,
|
|
280
|
+
reasoning: null,
|
|
281
|
+
toolCalls: [],
|
|
282
|
+
finishReason: mapFinishReason(firstChoice.finishReason),
|
|
283
|
+
usage: mapUsage(response.usage)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
238
286
|
const parts = extractAssistantParts(firstChoice.message);
|
|
239
287
|
const toolCalls = parts.flatMap(
|
|
240
288
|
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
@@ -535,39 +583,165 @@ function toObject(value) {
|
|
|
535
583
|
}
|
|
536
584
|
|
|
537
585
|
// src/mistral-error.ts
|
|
538
|
-
import {
|
|
539
|
-
|
|
540
|
-
|
|
586
|
+
import {
|
|
587
|
+
RequestAbortedError,
|
|
588
|
+
RequestTimeoutError,
|
|
589
|
+
MistralError
|
|
590
|
+
} from "@mistralai/mistralai/models/errors";
|
|
591
|
+
import {
|
|
592
|
+
AbortedError,
|
|
593
|
+
ContextLengthExceededError,
|
|
594
|
+
ModelOverloadedError,
|
|
595
|
+
ProviderError,
|
|
596
|
+
RateLimitError,
|
|
597
|
+
ServiceUnavailableError,
|
|
598
|
+
asRecord,
|
|
599
|
+
getErrorMessage,
|
|
600
|
+
getHttpStatusCode,
|
|
601
|
+
getRetryAfterSecondsFromError,
|
|
602
|
+
getString,
|
|
603
|
+
isAbortErrorByName,
|
|
604
|
+
isRateLimitStatus,
|
|
605
|
+
isTransientUnavailableStatus
|
|
606
|
+
} from "@core-ai/core-ai";
|
|
607
|
+
var OVERLOAD_MESSAGE_ELIGIBLE_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
|
|
541
608
|
function wrapMistralError(error) {
|
|
542
|
-
if (error
|
|
609
|
+
if (isMistralAbortError(error)) {
|
|
543
610
|
return new AbortedError(error, "mistral");
|
|
544
611
|
}
|
|
545
|
-
if (error
|
|
546
|
-
return new
|
|
547
|
-
error
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
612
|
+
if (isMistralTimeoutError(error)) {
|
|
613
|
+
return new ServiceUnavailableError(getErrorMessage(error), "mistral", {
|
|
614
|
+
cause: error
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
const message = getErrorMessage(error);
|
|
618
|
+
const statusCode = error instanceof MistralError ? error.statusCode : getHttpStatusCode(error, ["statusCode", "status"]);
|
|
619
|
+
const body = parseErrorBody(error);
|
|
620
|
+
const options = { statusCode, cause: error };
|
|
621
|
+
const contextLength = getContextLengthDetails(body, message);
|
|
622
|
+
if (contextLength) {
|
|
623
|
+
return new ContextLengthExceededError(message, "mistral", {
|
|
624
|
+
...options,
|
|
625
|
+
...contextLength
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (indicatesMistralOverload(message, statusCode)) {
|
|
629
|
+
return new ModelOverloadedError(message, "mistral", options);
|
|
630
|
+
}
|
|
631
|
+
if (isMistralRateLimit(statusCode, body?.type)) {
|
|
632
|
+
return new RateLimitError(message, "mistral", {
|
|
633
|
+
...options,
|
|
634
|
+
retryAfterSeconds: getRetryAfterSecondsFromError(error)
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (isTransientUnavailableStatus(statusCode)) {
|
|
638
|
+
return new ServiceUnavailableError(message, "mistral", options);
|
|
639
|
+
}
|
|
640
|
+
return new ProviderError(message, "mistral", options);
|
|
641
|
+
}
|
|
642
|
+
function isMistralAbortError(error) {
|
|
643
|
+
return error instanceof RequestAbortedError || isAbortErrorByName(error);
|
|
644
|
+
}
|
|
645
|
+
function isMistralTimeoutError(error) {
|
|
646
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "RequestTimeoutError";
|
|
647
|
+
}
|
|
648
|
+
function isMistralRateLimit(statusCode, errorType) {
|
|
649
|
+
return isRateLimitStatus(statusCode) || errorType === "rate_limit_error";
|
|
650
|
+
}
|
|
651
|
+
function indicatesMistralOverload(text, statusCode) {
|
|
652
|
+
if (statusCode !== void 0 && !OVERLOAD_MESSAGE_ELIGIBLE_STATUS_CODES.has(statusCode)) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
return /\boverloaded\b/i.test(text);
|
|
656
|
+
}
|
|
657
|
+
function getContextLengthDetails(body, message) {
|
|
658
|
+
const errorMessage = resolveMistralMessageText(body?.message ?? message);
|
|
659
|
+
const errorType = body?.type;
|
|
660
|
+
const isContextType = errorType === "invalid_request_error" || errorType === "invalid_request_invalid_args" || errorType === void 0;
|
|
661
|
+
if (!isContextType) {
|
|
662
|
+
return void 0;
|
|
552
663
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
void 0
|
|
557
|
-
|
|
664
|
+
const lower = errorMessage.toLowerCase();
|
|
665
|
+
const isContextWording = lower.includes("too large for model") || /exceeds the model's maximum context length/i.test(errorMessage);
|
|
666
|
+
if (!isContextWording) {
|
|
667
|
+
return void 0;
|
|
668
|
+
}
|
|
669
|
+
const match = errorMessage.match(
|
|
670
|
+
/(\d+)\s*tokens.*too large for model with (\d+) maximum context length/
|
|
558
671
|
);
|
|
672
|
+
if (!match) {
|
|
673
|
+
const alternate = errorMessage.match(
|
|
674
|
+
/exceeds the model's maximum context length of (\d+)/i
|
|
675
|
+
);
|
|
676
|
+
if (alternate?.[1]) {
|
|
677
|
+
return { maxTokens: parseInt(alternate[1], 10) };
|
|
678
|
+
}
|
|
679
|
+
return {};
|
|
680
|
+
}
|
|
681
|
+
const actualTokens = match[1];
|
|
682
|
+
const maxTokens = match[2];
|
|
683
|
+
if (actualTokens === void 0 || maxTokens === void 0) {
|
|
684
|
+
return {};
|
|
685
|
+
}
|
|
686
|
+
return {
|
|
687
|
+
maxTokens: parseInt(maxTokens, 10),
|
|
688
|
+
actualTokens: parseInt(actualTokens, 10)
|
|
689
|
+
};
|
|
559
690
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
supported: false,
|
|
565
|
-
supportedEfforts: [],
|
|
566
|
-
restrictsSamplingParams: false
|
|
691
|
+
function resolveMistralMessageText(message) {
|
|
692
|
+
const trimmed = message.trim();
|
|
693
|
+
if (!trimmed.startsWith("{")) {
|
|
694
|
+
return message;
|
|
567
695
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
696
|
+
try {
|
|
697
|
+
const parsed = JSON.parse(trimmed);
|
|
698
|
+
const record = asRecord(parsed);
|
|
699
|
+
const nestedMessage = getString(record, "message");
|
|
700
|
+
if (nestedMessage) {
|
|
701
|
+
return nestedMessage;
|
|
702
|
+
}
|
|
703
|
+
} catch {
|
|
704
|
+
}
|
|
705
|
+
return message;
|
|
706
|
+
}
|
|
707
|
+
function parseErrorBody(error) {
|
|
708
|
+
const record = asRecord(error);
|
|
709
|
+
if (!record || !("body" in record)) {
|
|
710
|
+
const type = getString(record, "type");
|
|
711
|
+
const message = getString(record, "message");
|
|
712
|
+
if (type || message) {
|
|
713
|
+
return {
|
|
714
|
+
type,
|
|
715
|
+
message: message ? resolveMistralMessageText(message) : void 0
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
return void 0;
|
|
719
|
+
}
|
|
720
|
+
const body = record.body;
|
|
721
|
+
if (typeof body !== "string") {
|
|
722
|
+
if (body && typeof body === "object") {
|
|
723
|
+
const bodyRecord = asRecord(body);
|
|
724
|
+
const message = getString(bodyRecord, "message");
|
|
725
|
+
return {
|
|
726
|
+
message: message ? resolveMistralMessageText(message) : void 0,
|
|
727
|
+
type: getString(bodyRecord, "type")
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
return void 0;
|
|
731
|
+
}
|
|
732
|
+
try {
|
|
733
|
+
const parsed = JSON.parse(body);
|
|
734
|
+
const parsedRecord = asRecord(parsed);
|
|
735
|
+
if (parsedRecord) {
|
|
736
|
+
const message = getString(parsedRecord, "message");
|
|
737
|
+
return {
|
|
738
|
+
message: message ? resolveMistralMessageText(message) : void 0,
|
|
739
|
+
type: getString(parsedRecord, "type")
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
} catch {
|
|
743
|
+
}
|
|
744
|
+
return void 0;
|
|
571
745
|
}
|
|
572
746
|
|
|
573
747
|
// src/chat-model.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@core-ai/mistral",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Mistral provider package for @core-ai/core-ai",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Omnifact (https://omnifact.ai)",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"test:watch": "vitest"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@core-ai/core-ai": "^0.
|
|
47
|
-
"@mistralai/mistralai": "^
|
|
46
|
+
"@core-ai/core-ai": "^0.17.0",
|
|
47
|
+
"@mistralai/mistralai": "^2.4.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"zod": "^4.0.0"
|