@core-ai/mistral 0.16.0 → 0.18.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 +192 -32
- package/package.json +2 -2
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,
|
|
@@ -195,9 +228,12 @@ function createStreamRequest(modelId, options) {
|
|
|
195
228
|
return mapMistralProviderOptionsToRequest(baseRequest, mistralOptions);
|
|
196
229
|
}
|
|
197
230
|
function createRequestBase(modelId, options) {
|
|
231
|
+
const capabilities = getMistralModelCapabilities(modelId);
|
|
198
232
|
return {
|
|
199
233
|
model: modelId,
|
|
200
|
-
messages: convertMessages(options.messages
|
|
234
|
+
messages: convertMessages(options.messages, {
|
|
235
|
+
includeReasoning: capabilities.reasoning.mode !== "unsupported"
|
|
236
|
+
}),
|
|
201
237
|
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
202
238
|
...options.toolChoice ? { toolChoice: convertToolChoice(options.toolChoice) } : {},
|
|
203
239
|
...mapSamplingToRequestFields(options)
|
|
@@ -549,39 +585,163 @@ function toObject(value) {
|
|
|
549
585
|
// src/mistral-error.ts
|
|
550
586
|
import {
|
|
551
587
|
RequestAbortedError,
|
|
588
|
+
RequestTimeoutError,
|
|
552
589
|
MistralError
|
|
553
590
|
} from "@mistralai/mistralai/models/errors";
|
|
554
|
-
import {
|
|
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]);
|
|
555
608
|
function wrapMistralError(error) {
|
|
556
|
-
if (error
|
|
609
|
+
if (isMistralAbortError(error)) {
|
|
557
610
|
return new AbortedError(error, "mistral");
|
|
558
611
|
}
|
|
559
|
-
if (error
|
|
560
|
-
return new
|
|
561
|
-
error
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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;
|
|
663
|
+
}
|
|
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;
|
|
566
668
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
"mistral",
|
|
570
|
-
void 0,
|
|
571
|
-
error
|
|
669
|
+
const match = errorMessage.match(
|
|
670
|
+
/(\d+)\s*tokens.*too large for model with (\d+) maximum context length/
|
|
572
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
|
+
};
|
|
573
690
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
supported: false,
|
|
579
|
-
supportedEfforts: [],
|
|
580
|
-
restrictsSamplingParams: false
|
|
691
|
+
function resolveMistralMessageText(message) {
|
|
692
|
+
const trimmed = message.trim();
|
|
693
|
+
if (!trimmed.startsWith("{")) {
|
|
694
|
+
return message;
|
|
581
695
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
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;
|
|
585
745
|
}
|
|
586
746
|
|
|
587
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.18.0",
|
|
4
4
|
"description": "Mistral provider package for @core-ai/core-ai",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Omnifact (https://omnifact.ai)",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test:watch": "vitest"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@core-ai/core-ai": "^0.
|
|
46
|
+
"@core-ai/core-ai": "^0.18.0",
|
|
47
47
|
"@mistralai/mistralai": "^2.4.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|