@goah/cli 0.13.0 → 0.13.2
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/LICENSE +201 -0
- package/dist/THIRD-PARTY-NOTICES.md +2319 -0
- package/dist/anthropic-messages-WBFOHES5.js +7214 -0
- package/dist/azure-openai-responses-NZFH3PO6.js +253 -0
- package/dist/chunk-25XSBFX6.js +639 -0
- package/dist/chunk-2QBQZGXF.js +110 -0
- package/dist/chunk-2ZP2NBW3.js +345 -0
- package/dist/chunk-4KA63VNZ.js +2 -0
- package/dist/chunk-4M6TXTT5.js +86 -0
- package/dist/chunk-4US7ZHT3.js +20 -0
- package/dist/chunk-6M3OOCKO.js +11809 -0
- package/dist/chunk-7AXAFDPG.js +17 -0
- package/dist/chunk-7E7V6OIU.js +920 -0
- package/dist/chunk-BXA47DTF.js +548 -0
- package/dist/chunk-D2DVAH37.js +25 -0
- package/dist/chunk-FSBUS2BI.js +26 -0
- package/dist/chunk-GKDRAHLI.js +4787 -0
- package/dist/chunk-H462EFJP.js +89 -0
- package/dist/chunk-IIJQ3DW4.js +35 -0
- package/dist/chunk-JQD5EWJY.js +34 -0
- package/dist/chunk-K26BVR6O.js +61 -0
- package/dist/chunk-KAO7WIXG.js +31 -0
- package/dist/chunk-KJ4HJCTK.js +1178 -0
- package/dist/chunk-LBKI23CC.js +9810 -0
- package/dist/chunk-LKBKZEHT.js +41 -0
- package/dist/chunk-MD7TLTXZ.js +18 -0
- package/dist/chunk-MPXK7QBL.js +868 -0
- package/dist/chunk-NRLGWZJC.js +11 -0
- package/dist/chunk-QBD6EJ2Z.js +1746 -0
- package/dist/chunk-R6I3VKME.js +132 -0
- package/dist/chunk-TJON22J4.js +87 -0
- package/dist/chunk-ULY36ME4.js +33097 -0
- package/dist/chunk-XALZLRYK.js +9221 -0
- package/dist/chunk-XPQKM3L7.js +57 -0
- package/dist/chunk-YH6YJ2IB.js +1773 -0
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +13716 -580
- package/dist/console/assets/{index-Rtc_B7cs.js → index-B1vGMXKr.js} +11 -11
- package/dist/console/assets/{index-Rtc_B7cs.js.map → index-B1vGMXKr.js.map} +1 -1
- package/dist/console/index.html +1 -1
- package/dist/dist-65MDQA4Q.js +1126 -0
- package/dist/dist-KNR2XL6J.js +39 -0
- package/dist/execution.d.ts +557 -2
- package/dist/execution.js +37 -2
- package/dist/faux-runner-worker.js +128 -0
- package/dist/google-generative-ai-YMHXZSFE.js +422 -0
- package/dist/google-vertex-X6DB3ZQ6.js +471 -0
- package/dist/index.d.ts +853 -25
- package/dist/index.js +84 -385
- package/dist/kernel.d.ts +39 -2
- package/dist/kernel.js +21 -2
- package/dist/mistral-conversations-TY3MMD6G.js +718 -0
- package/dist/multipart-parser-F6M4NJZU.js +373 -0
- package/dist/openai-codex-responses-BRDUMLN5.js +1374 -0
- package/dist/openai-completions-CX634XN3.js +1139 -0
- package/dist/openai-responses-HMCXJIHT.js +300 -0
- package/dist/openrouter-images-KTWET2H2.js +148 -0
- package/dist/pi-messages-XL5OEC4K.js +307 -0
- package/dist/pi-worker.js +671 -0
- package/dist/runner-pi.d.ts +342 -2
- package/dist/runner-pi.js +46 -2
- package/dist/runner-registry-GD4BYCQC.js +22 -0
- package/dist/sqlite.d.ts +446 -2
- package/dist/sqlite.js +15 -2
- package/dist/src-F2KBSV4T.js +1398 -0
- package/dist/supervisor.d.ts +625 -2
- package/dist/supervisor.js +39 -2
- package/dist/testkit.d.ts +564 -2
- package/dist/testkit.js +127 -2
- package/dist/transcript.d.ts +84 -2
- package/dist/transcript.js +25 -2
- package/dist/verification-worker.js +72 -0
- package/package.json +2 -26
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/control.d.ts +0 -106
- package/dist/control.d.ts.map +0 -1
- package/dist/control.js +0 -242
- package/dist/control.js.map +0 -1
- package/dist/execution.d.ts.map +0 -1
- package/dist/execution.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kernel.d.ts.map +0 -1
- package/dist/kernel.js.map +0 -1
- package/dist/live-config.d.ts +0 -10
- package/dist/live-config.d.ts.map +0 -1
- package/dist/live-config.js +0 -44
- package/dist/live-config.js.map +0 -1
- package/dist/prompt-queue.d.ts +0 -13
- package/dist/prompt-queue.d.ts.map +0 -1
- package/dist/prompt-queue.js +0 -35
- package/dist/prompt-queue.js.map +0 -1
- package/dist/runner-pi.d.ts.map +0 -1
- package/dist/runner-pi.js.map +0 -1
- package/dist/runner-registry.d.ts +0 -8
- package/dist/runner-registry.d.ts.map +0 -1
- package/dist/runner-registry.js +0 -12
- package/dist/runner-registry.js.map +0 -1
- package/dist/searchable-select.d.ts +0 -24
- package/dist/searchable-select.d.ts.map +0 -1
- package/dist/searchable-select.js +0 -61
- package/dist/searchable-select.js.map +0 -1
- package/dist/secret-input.d.ts +0 -8
- package/dist/secret-input.d.ts.map +0 -1
- package/dist/secret-input.js +0 -14
- package/dist/secret-input.js.map +0 -1
- package/dist/setup-wizard.d.ts +0 -22
- package/dist/setup-wizard.d.ts.map +0 -1
- package/dist/setup-wizard.js +0 -154
- package/dist/setup-wizard.js.map +0 -1
- package/dist/sqlite.d.ts.map +0 -1
- package/dist/sqlite.js.map +0 -1
- package/dist/supervisor.d.ts.map +0 -1
- package/dist/supervisor.js.map +0 -1
- package/dist/testkit.d.ts.map +0 -1
- package/dist/testkit.js.map +0 -1
- package/dist/thread-inspect.d.ts +0 -47
- package/dist/thread-inspect.d.ts.map +0 -1
- package/dist/thread-inspect.js +0 -78
- package/dist/thread-inspect.js.map +0 -1
- package/dist/transcript.d.ts.map +0 -1
- package/dist/transcript.js.map +0 -1
- package/dist/tui-theme.d.ts +0 -17
- package/dist/tui-theme.d.ts.map +0 -1
- package/dist/tui-theme.js +0 -19
- package/dist/tui-theme.js.map +0 -1
- package/dist/tui.d.ts +0 -24
- package/dist/tui.d.ts.map +0 -1
- package/dist/tui.js +0 -784
- package/dist/tui.js.map +0 -1
- package/dist/update.d.ts +0 -16
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js +0 -67
- package/dist/update.js.map +0 -1
- package/dist/web-console.d.ts +0 -33
- package/dist/web-console.d.ts.map +0 -1
- package/dist/web-console.js +0 -242
- package/dist/web-console.js.map +0 -1
- package/dist/welcome.d.ts +0 -30
- package/dist/welcome.d.ts.map +0 -1
- package/dist/welcome.js +0 -69
- package/dist/welcome.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/execution.d.ts +0 -544
- package/node_modules/goah-ledger-contract/dist/execution.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/execution.js +0 -52
- package/node_modules/goah-ledger-contract/dist/execution.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/index.d.ts +0 -4
- package/node_modules/goah-ledger-contract/dist/index.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/index.js +0 -4
- package/node_modules/goah-ledger-contract/dist/index.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/kernel.d.ts +0 -37
- package/node_modules/goah-ledger-contract/dist/kernel.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/kernel.js +0 -8
- package/node_modules/goah-ledger-contract/dist/kernel.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/transcript.d.ts +0 -63
- package/node_modules/goah-ledger-contract/dist/transcript.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/transcript.js +0 -115
- package/node_modules/goah-ledger-contract/dist/transcript.js.map +0 -1
- package/node_modules/goah-ledger-contract/package.json +0 -28
- package/node_modules/goah-ledger-sqlite/dist/index.d.ts +0 -86
- package/node_modules/goah-ledger-sqlite/dist/index.d.ts.map +0 -1
- package/node_modules/goah-ledger-sqlite/dist/index.js +0 -1254
- package/node_modules/goah-ledger-sqlite/dist/index.js.map +0 -1
- package/node_modules/goah-ledger-sqlite/package.json +0 -26
- package/node_modules/goah-runner-pi/dist/configurator.d.ts +0 -20
- package/node_modules/goah-runner-pi/dist/configurator.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/configurator.js +0 -423
- package/node_modules/goah-runner-pi/dist/configurator.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/credential-store.d.ts +0 -14
- package/node_modules/goah-runner-pi/dist/credential-store.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/credential-store.js +0 -163
- package/node_modules/goah-runner-pi/dist/credential-store.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/env-spec.d.ts +0 -17
- package/node_modules/goah-runner-pi/dist/env-spec.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/env-spec.js +0 -95
- package/node_modules/goah-runner-pi/dist/env-spec.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/index.d.ts +0 -76
- package/node_modules/goah-runner-pi/dist/index.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/index.js +0 -326
- package/node_modules/goah-runner-pi/dist/index.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/model-provider.d.ts +0 -30
- package/node_modules/goah-runner-pi/dist/model-provider.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/model-provider.js +0 -96
- package/node_modules/goah-runner-pi/dist/model-provider.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/pi-worker.d.ts +0 -31
- package/node_modules/goah-runner-pi/dist/pi-worker.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/pi-worker.js +0 -579
- package/node_modules/goah-runner-pi/dist/pi-worker.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.d.ts +0 -2
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.js +0 -3
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.d.ts +0 -2
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.js +0 -5
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.d.ts +0 -2
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.js +0 -5
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/test-helpers.d.ts +0 -4
- package/node_modules/goah-runner-pi/dist/test-helpers.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/test-helpers.js +0 -13
- package/node_modules/goah-runner-pi/dist/test-helpers.js.map +0 -1
- package/node_modules/goah-runner-pi/dist/verification-worker.d.ts +0 -2
- package/node_modules/goah-runner-pi/dist/verification-worker.d.ts.map +0 -1
- package/node_modules/goah-runner-pi/dist/verification-worker.js +0 -46
- package/node_modules/goah-runner-pi/dist/verification-worker.js.map +0 -1
- package/node_modules/goah-runner-pi/package.json +0 -28
- package/node_modules/goah-supervisor/dist/context-view.d.ts +0 -30
- package/node_modules/goah-supervisor/dist/context-view.d.ts.map +0 -1
- package/node_modules/goah-supervisor/dist/context-view.js +0 -58
- package/node_modules/goah-supervisor/dist/context-view.js.map +0 -1
- package/node_modules/goah-supervisor/dist/index.d.ts +0 -96
- package/node_modules/goah-supervisor/dist/index.d.ts.map +0 -1
- package/node_modules/goah-supervisor/dist/index.js +0 -1075
- package/node_modules/goah-supervisor/dist/index.js.map +0 -1
- package/node_modules/goah-supervisor/dist/roles.d.ts +0 -4
- package/node_modules/goah-supervisor/dist/roles.d.ts.map +0 -1
- package/node_modules/goah-supervisor/dist/roles.js +0 -29
- package/node_modules/goah-supervisor/dist/roles.js.map +0 -1
- package/node_modules/goah-supervisor/dist/verification.d.ts +0 -61
- package/node_modules/goah-supervisor/dist/verification.d.ts.map +0 -1
- package/node_modules/goah-supervisor/dist/verification.js +0 -135
- package/node_modules/goah-supervisor/dist/verification.js.map +0 -1
- package/node_modules/goah-supervisor/package.json +0 -26
- package/node_modules/goah-testkit/dist/faux-runner-worker.d.ts +0 -2
- package/node_modules/goah-testkit/dist/faux-runner-worker.d.ts.map +0 -1
- package/node_modules/goah-testkit/dist/faux-runner-worker.js +0 -82
- package/node_modules/goah-testkit/dist/faux-runner-worker.js.map +0 -1
- package/node_modules/goah-testkit/dist/index.d.ts +0 -49
- package/node_modules/goah-testkit/dist/index.d.ts.map +0 -1
- package/node_modules/goah-testkit/dist/index.js +0 -96
- package/node_modules/goah-testkit/dist/index.js.map +0 -1
- package/node_modules/goah-testkit/package.json +0 -29
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
import { createRequire as __goahCreateRequire } from "node:module";
|
|
2
|
+
const require = __goahCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
shortHash
|
|
5
|
+
} from "./chunk-4US7ZHT3.js";
|
|
6
|
+
import {
|
|
7
|
+
buildBaseOptions,
|
|
8
|
+
getJsonSchemaToolParameters,
|
|
9
|
+
resolveJsonSchemaStrictSampling,
|
|
10
|
+
transformMessages
|
|
11
|
+
} from "./chunk-BXA47DTF.js";
|
|
12
|
+
import {
|
|
13
|
+
sanitizeSurrogates
|
|
14
|
+
} from "./chunk-NRLGWZJC.js";
|
|
15
|
+
import {
|
|
16
|
+
headersToRecord
|
|
17
|
+
} from "./chunk-FSBUS2BI.js";
|
|
18
|
+
import {
|
|
19
|
+
parseStreamingJson
|
|
20
|
+
} from "./chunk-2ZP2NBW3.js";
|
|
21
|
+
import {
|
|
22
|
+
calculateCost,
|
|
23
|
+
clampThinkingLevel
|
|
24
|
+
} from "./chunk-MPXK7QBL.js";
|
|
25
|
+
import {
|
|
26
|
+
AssistantMessageEventStream
|
|
27
|
+
} from "./chunk-2QBQZGXF.js";
|
|
28
|
+
import "./chunk-XPQKM3L7.js";
|
|
29
|
+
|
|
30
|
+
// ../../node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js
|
|
31
|
+
var MISTRAL_TOOL_CALL_ID_LENGTH = 9;
|
|
32
|
+
var MAX_MISTRAL_ERROR_BODY_CHARS = 4e3;
|
|
33
|
+
var stream = (model, context, options) => {
|
|
34
|
+
const stream2 = new AssistantMessageEventStream();
|
|
35
|
+
(async () => {
|
|
36
|
+
const output = createOutput(model);
|
|
37
|
+
try {
|
|
38
|
+
const apiKey = options?.apiKey;
|
|
39
|
+
if (!apiKey) {
|
|
40
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
41
|
+
}
|
|
42
|
+
const normalizeMistralToolCallId = createMistralToolCallIdNormalizer();
|
|
43
|
+
const transformedMessages = transformMessages(context.messages, model, (id) => normalizeMistralToolCallId(id));
|
|
44
|
+
let payload = buildChatPayload(model, context, transformedMessages, options);
|
|
45
|
+
const nextPayload = await options?.onPayload?.(payload, model);
|
|
46
|
+
if (nextPayload !== void 0) {
|
|
47
|
+
payload = nextPayload;
|
|
48
|
+
}
|
|
49
|
+
const mistralStream = await requestMistralStream(model, payload, apiKey, options);
|
|
50
|
+
stream2.push({ type: "start", partial: output });
|
|
51
|
+
await consumeChatStream(model, output, stream2, mistralStream);
|
|
52
|
+
if (options?.signal?.aborted) {
|
|
53
|
+
throw new Error("Request was aborted");
|
|
54
|
+
}
|
|
55
|
+
if (output.stopReason === "pending") {
|
|
56
|
+
throw new Error("Mistral stream ended without a finish reason");
|
|
57
|
+
}
|
|
58
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") {
|
|
59
|
+
throw new Error(output.errorMessage || "An unknown error occurred");
|
|
60
|
+
}
|
|
61
|
+
stream2.push({ type: "done", reason: output.stopReason, message: output });
|
|
62
|
+
stream2.end();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
for (const block of output.content) {
|
|
65
|
+
delete block.partialArgs;
|
|
66
|
+
}
|
|
67
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
68
|
+
output.errorMessage = formatMistralError(error);
|
|
69
|
+
stream2.push({ type: "error", reason: output.stopReason, error: output });
|
|
70
|
+
stream2.end();
|
|
71
|
+
}
|
|
72
|
+
})();
|
|
73
|
+
return stream2;
|
|
74
|
+
};
|
|
75
|
+
var streamSimple = (model, context, options) => {
|
|
76
|
+
const apiKey = options?.apiKey;
|
|
77
|
+
if (!apiKey) {
|
|
78
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
79
|
+
}
|
|
80
|
+
const base = buildBaseOptions(model, context, options, apiKey);
|
|
81
|
+
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;
|
|
82
|
+
const reasoning = clampedReasoning === "off" ? void 0 : clampedReasoning;
|
|
83
|
+
const shouldUseReasoning = model.reasoning && reasoning !== void 0;
|
|
84
|
+
return stream(model, context, {
|
|
85
|
+
...base,
|
|
86
|
+
promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? "reasoning" : void 0,
|
|
87
|
+
reasoningEffort: shouldUseReasoning && usesReasoningEffort(model) ? mapReasoningEffort(model, reasoning) : void 0
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
function createOutput(model) {
|
|
91
|
+
return {
|
|
92
|
+
role: "assistant",
|
|
93
|
+
content: [],
|
|
94
|
+
api: model.api,
|
|
95
|
+
provider: model.provider,
|
|
96
|
+
model: model.id,
|
|
97
|
+
usage: {
|
|
98
|
+
input: 0,
|
|
99
|
+
output: 0,
|
|
100
|
+
cacheRead: 0,
|
|
101
|
+
cacheWrite: 0,
|
|
102
|
+
totalTokens: 0,
|
|
103
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
104
|
+
},
|
|
105
|
+
stopReason: "pending",
|
|
106
|
+
timestamp: Date.now()
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function createMistralToolCallIdNormalizer() {
|
|
110
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
111
|
+
const reverseMap = /* @__PURE__ */ new Map();
|
|
112
|
+
return (id) => {
|
|
113
|
+
const existing = idMap.get(id);
|
|
114
|
+
if (existing)
|
|
115
|
+
return existing;
|
|
116
|
+
let attempt = 0;
|
|
117
|
+
while (true) {
|
|
118
|
+
const candidate = deriveMistralToolCallId(id, attempt);
|
|
119
|
+
const owner = reverseMap.get(candidate);
|
|
120
|
+
if (!owner || owner === id) {
|
|
121
|
+
idMap.set(id, candidate);
|
|
122
|
+
reverseMap.set(candidate, id);
|
|
123
|
+
return candidate;
|
|
124
|
+
}
|
|
125
|
+
attempt++;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function deriveMistralToolCallId(id, attempt) {
|
|
130
|
+
const normalized = id.replace(/[^a-zA-Z0-9]/g, "");
|
|
131
|
+
if (attempt === 0 && normalized.length === MISTRAL_TOOL_CALL_ID_LENGTH)
|
|
132
|
+
return normalized;
|
|
133
|
+
const seedBase = normalized || id;
|
|
134
|
+
const seed = attempt === 0 ? seedBase : `${seedBase}:${attempt}`;
|
|
135
|
+
return shortHash(seed).replace(/[^a-zA-Z0-9]/g, "").slice(0, MISTRAL_TOOL_CALL_ID_LENGTH);
|
|
136
|
+
}
|
|
137
|
+
function formatMistralError(error) {
|
|
138
|
+
if (error instanceof Error) {
|
|
139
|
+
const httpError = error;
|
|
140
|
+
const statusCode = typeof httpError.statusCode === "number" ? httpError.statusCode : void 0;
|
|
141
|
+
const bodyText = typeof httpError.body === "string" ? httpError.body.trim() : void 0;
|
|
142
|
+
if (statusCode !== void 0 && bodyText) {
|
|
143
|
+
return `Mistral API error (${statusCode}): ${truncateErrorText(bodyText, MAX_MISTRAL_ERROR_BODY_CHARS)}`;
|
|
144
|
+
}
|
|
145
|
+
if (statusCode !== void 0)
|
|
146
|
+
return `Mistral API error (${statusCode}): ${error.message}`;
|
|
147
|
+
return error.message;
|
|
148
|
+
}
|
|
149
|
+
return safeJsonStringify(error);
|
|
150
|
+
}
|
|
151
|
+
function truncateErrorText(text, maxChars) {
|
|
152
|
+
if (text.length <= maxChars)
|
|
153
|
+
return text;
|
|
154
|
+
return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
|
|
155
|
+
}
|
|
156
|
+
function safeJsonStringify(value) {
|
|
157
|
+
try {
|
|
158
|
+
const serialized = JSON.stringify(value);
|
|
159
|
+
return serialized === void 0 ? String(value) : serialized;
|
|
160
|
+
} catch {
|
|
161
|
+
return String(value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function requestMistralStream(model, payload, apiKey, options) {
|
|
165
|
+
const baseUrl = new URL(model.baseUrl);
|
|
166
|
+
baseUrl.pathname = `${baseUrl.pathname.replace(/\/+$/u, "")}/`;
|
|
167
|
+
const url = new URL("v1/chat/completions", baseUrl);
|
|
168
|
+
const headers = buildMistralHeaders(model, apiKey, options);
|
|
169
|
+
const timeoutSignal = AbortSignal.timeout(options?.timeoutMs ?? 6e4);
|
|
170
|
+
const signal = options?.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
|
|
171
|
+
const response = await (options?.fetch ?? globalThis.fetch)(url, {
|
|
172
|
+
method: "POST",
|
|
173
|
+
headers,
|
|
174
|
+
body: JSON.stringify(toMistralWirePayload(payload)),
|
|
175
|
+
signal
|
|
176
|
+
});
|
|
177
|
+
await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
const body = await response.text();
|
|
180
|
+
throw new MistralHttpError(response.status, body, response.statusText);
|
|
181
|
+
}
|
|
182
|
+
if (!response.body) {
|
|
183
|
+
throw new Error("Mistral response has no body");
|
|
184
|
+
}
|
|
185
|
+
return readMistralEvents(response.body, signal);
|
|
186
|
+
}
|
|
187
|
+
var MistralHttpError = class extends Error {
|
|
188
|
+
statusCode;
|
|
189
|
+
body;
|
|
190
|
+
constructor(statusCode, body, statusText) {
|
|
191
|
+
super(statusText || `Request failed with status ${statusCode}`);
|
|
192
|
+
this.name = "MistralHttpError";
|
|
193
|
+
this.statusCode = statusCode;
|
|
194
|
+
this.body = body;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function buildMistralHeaders(model, apiKey, options) {
|
|
198
|
+
const headers = new Headers({
|
|
199
|
+
accept: "text/event-stream",
|
|
200
|
+
authorization: `Bearer ${apiKey}`,
|
|
201
|
+
"content-type": "application/json"
|
|
202
|
+
});
|
|
203
|
+
applyMistralHeaderOverrides(headers, model.headers);
|
|
204
|
+
applyMistralHeaderOverrides(headers, options?.headers);
|
|
205
|
+
const hasExplicitAffinity = hasMistralHeaderOverride(model.headers, "x-affinity") || hasMistralHeaderOverride(options?.headers, "x-affinity");
|
|
206
|
+
if (shouldUsePromptCaching(options) && !hasExplicitAffinity) {
|
|
207
|
+
headers.set("x-affinity", options.sessionId);
|
|
208
|
+
}
|
|
209
|
+
return headers;
|
|
210
|
+
}
|
|
211
|
+
function applyMistralHeaderOverrides(headers, overrides) {
|
|
212
|
+
if (!overrides)
|
|
213
|
+
return;
|
|
214
|
+
for (const [name, value] of Object.entries(overrides)) {
|
|
215
|
+
if (value === null)
|
|
216
|
+
headers.delete(name);
|
|
217
|
+
else
|
|
218
|
+
headers.set(name, value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function hasMistralHeaderOverride(overrides, target) {
|
|
222
|
+
return !!overrides && Object.keys(overrides).some((name) => name.toLowerCase() === target);
|
|
223
|
+
}
|
|
224
|
+
function toMistralWirePayload(payload) {
|
|
225
|
+
const wirePayload = { ...payload };
|
|
226
|
+
for (const [source, target] of [
|
|
227
|
+
["topP", "top_p"],
|
|
228
|
+
["maxTokens", "max_tokens"],
|
|
229
|
+
["randomSeed", "random_seed"],
|
|
230
|
+
["responseFormat", "response_format"],
|
|
231
|
+
["toolChoice", "tool_choice"],
|
|
232
|
+
["presencePenalty", "presence_penalty"],
|
|
233
|
+
["frequencyPenalty", "frequency_penalty"],
|
|
234
|
+
["parallelToolCalls", "parallel_tool_calls"],
|
|
235
|
+
["reasoningEffort", "reasoning_effort"],
|
|
236
|
+
["promptMode", "prompt_mode"],
|
|
237
|
+
["promptCacheKey", "prompt_cache_key"],
|
|
238
|
+
["safePrompt", "safe_prompt"]
|
|
239
|
+
]) {
|
|
240
|
+
remapMistralProperty(wirePayload, source, target);
|
|
241
|
+
}
|
|
242
|
+
wirePayload.messages = payload.messages.map((message) => toMistralWireMessage(message));
|
|
243
|
+
const responseFormat = wirePayload.response_format;
|
|
244
|
+
if (isMistralRecord(responseFormat)) {
|
|
245
|
+
const wireResponseFormat = { ...responseFormat };
|
|
246
|
+
remapMistralProperty(wireResponseFormat, "jsonSchema", "json_schema");
|
|
247
|
+
const jsonSchema = wireResponseFormat.json_schema;
|
|
248
|
+
if (isMistralRecord(jsonSchema)) {
|
|
249
|
+
const wireJsonSchema = { ...jsonSchema };
|
|
250
|
+
remapMistralProperty(wireJsonSchema, "schemaDefinition", "schema");
|
|
251
|
+
wireResponseFormat.json_schema = wireJsonSchema;
|
|
252
|
+
}
|
|
253
|
+
wirePayload.response_format = wireResponseFormat;
|
|
254
|
+
}
|
|
255
|
+
return wirePayload;
|
|
256
|
+
}
|
|
257
|
+
function toMistralWireMessage(message) {
|
|
258
|
+
const wireMessage = { ...message };
|
|
259
|
+
remapMistralProperty(wireMessage, "toolCalls", "tool_calls");
|
|
260
|
+
remapMistralProperty(wireMessage, "toolCallId", "tool_call_id");
|
|
261
|
+
if (Array.isArray(message.content)) {
|
|
262
|
+
wireMessage.content = message.content.map((chunk) => toMistralWireContentChunk(chunk));
|
|
263
|
+
}
|
|
264
|
+
return wireMessage;
|
|
265
|
+
}
|
|
266
|
+
function toMistralWireContentChunk(chunk) {
|
|
267
|
+
const wireChunk = { ...chunk };
|
|
268
|
+
for (const [source, target] of [
|
|
269
|
+
["imageUrl", "image_url"],
|
|
270
|
+
["documentUrl", "document_url"],
|
|
271
|
+
["documentName", "document_name"],
|
|
272
|
+
["fileId", "file_id"],
|
|
273
|
+
["referenceIds", "reference_ids"],
|
|
274
|
+
["inputAudio", "input_audio"]
|
|
275
|
+
]) {
|
|
276
|
+
remapMistralProperty(wireChunk, source, target);
|
|
277
|
+
}
|
|
278
|
+
return wireChunk;
|
|
279
|
+
}
|
|
280
|
+
function remapMistralProperty(record, source, target) {
|
|
281
|
+
if (!(source in record))
|
|
282
|
+
return;
|
|
283
|
+
record[target] = record[source];
|
|
284
|
+
delete record[source];
|
|
285
|
+
}
|
|
286
|
+
function isMistralRecord(value) {
|
|
287
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
288
|
+
}
|
|
289
|
+
var MISTRAL_STREAM_DONE = /* @__PURE__ */ Symbol("mistral-stream-done");
|
|
290
|
+
async function* readMistralEvents(body, signal) {
|
|
291
|
+
const reader = body.getReader();
|
|
292
|
+
const decoder = new TextDecoder();
|
|
293
|
+
let buffer = "";
|
|
294
|
+
const onAbort = () => {
|
|
295
|
+
void reader.cancel().catch(() => {
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
299
|
+
try {
|
|
300
|
+
while (true) {
|
|
301
|
+
if (signal.aborted)
|
|
302
|
+
throw signal.reason;
|
|
303
|
+
const { done, value } = await reader.read();
|
|
304
|
+
if (signal.aborted)
|
|
305
|
+
throw signal.reason;
|
|
306
|
+
buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
|
|
307
|
+
let boundary = findMistralEventBoundary(buffer);
|
|
308
|
+
while (boundary) {
|
|
309
|
+
const event = parseMistralEvent(buffer.slice(0, boundary.index));
|
|
310
|
+
buffer = buffer.slice(boundary.index + boundary.length);
|
|
311
|
+
if (event === MISTRAL_STREAM_DONE)
|
|
312
|
+
return;
|
|
313
|
+
if (event)
|
|
314
|
+
yield event;
|
|
315
|
+
boundary = findMistralEventBoundary(buffer);
|
|
316
|
+
}
|
|
317
|
+
if (done)
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
if (buffer.trim()) {
|
|
321
|
+
const event = parseMistralEvent(buffer);
|
|
322
|
+
if (event !== MISTRAL_STREAM_DONE && event)
|
|
323
|
+
yield event;
|
|
324
|
+
}
|
|
325
|
+
} finally {
|
|
326
|
+
signal.removeEventListener("abort", onAbort);
|
|
327
|
+
try {
|
|
328
|
+
await reader.cancel();
|
|
329
|
+
} catch {
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
reader.releaseLock();
|
|
333
|
+
} catch {
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function findMistralEventBoundary(buffer) {
|
|
338
|
+
const match = /\r\n\r\n|\r\n\r|\r\n\n|\r\r\n|\n\r\n|\r\r|\n\r|\n\n/u.exec(buffer);
|
|
339
|
+
return match?.index === void 0 ? void 0 : { index: match.index, length: match[0].length };
|
|
340
|
+
}
|
|
341
|
+
function parseMistralEvent(raw) {
|
|
342
|
+
const data = raw.split(/\r\n|\r|\n/u).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n").trim();
|
|
343
|
+
if (!data)
|
|
344
|
+
return void 0;
|
|
345
|
+
if (data === "[DONE]")
|
|
346
|
+
return MISTRAL_STREAM_DONE;
|
|
347
|
+
const parsed = JSON.parse(data);
|
|
348
|
+
if (!isMistralRecord(parsed) || !Array.isArray(parsed.choices)) {
|
|
349
|
+
throw new Error("Invalid Mistral streaming event");
|
|
350
|
+
}
|
|
351
|
+
return { data: parsed };
|
|
352
|
+
}
|
|
353
|
+
function buildChatPayload(model, context, messages, options) {
|
|
354
|
+
const payload = {
|
|
355
|
+
model: model.id,
|
|
356
|
+
stream: true,
|
|
357
|
+
messages: toChatMessages(messages, model.input.includes("image"))
|
|
358
|
+
};
|
|
359
|
+
if (context.tools?.length)
|
|
360
|
+
payload.tools = toFunctionTools(context.tools);
|
|
361
|
+
if (options?.temperature !== void 0)
|
|
362
|
+
payload.temperature = options.temperature;
|
|
363
|
+
if (options?.maxTokens !== void 0)
|
|
364
|
+
payload.maxTokens = options.maxTokens;
|
|
365
|
+
if (options?.toolChoice)
|
|
366
|
+
payload.toolChoice = mapToolChoice(options.toolChoice);
|
|
367
|
+
if (options?.promptMode)
|
|
368
|
+
payload.promptMode = options.promptMode;
|
|
369
|
+
if (options?.reasoningEffort)
|
|
370
|
+
payload.reasoningEffort = options.reasoningEffort;
|
|
371
|
+
if (shouldUsePromptCaching(options))
|
|
372
|
+
payload.promptCacheKey = options.sessionId;
|
|
373
|
+
if (context.systemPrompt) {
|
|
374
|
+
payload.messages.unshift({
|
|
375
|
+
role: "system",
|
|
376
|
+
content: sanitizeSurrogates(context.systemPrompt)
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return payload;
|
|
380
|
+
}
|
|
381
|
+
function shouldUsePromptCaching(options) {
|
|
382
|
+
return options?.cacheRetention !== "none" && !!options?.sessionId;
|
|
383
|
+
}
|
|
384
|
+
function getMistralCachedPromptTokens(usage, promptTokens) {
|
|
385
|
+
const rawUsage = usage;
|
|
386
|
+
const rawCachedTokens = rawUsage.promptTokensDetails?.cachedTokens ?? rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.promptTokenDetails?.cachedTokens ?? rawUsage.prompt_token_details?.cached_tokens ?? rawUsage.numCachedTokens ?? rawUsage.num_cached_tokens ?? 0;
|
|
387
|
+
const cachedTokens = typeof rawCachedTokens === "number" && Number.isFinite(rawCachedTokens) ? rawCachedTokens : 0;
|
|
388
|
+
return Math.min(promptTokens, Math.max(0, cachedTokens));
|
|
389
|
+
}
|
|
390
|
+
async function consumeChatStream(model, output, stream2, mistralStream) {
|
|
391
|
+
let currentBlock = null;
|
|
392
|
+
const blocks = output.content;
|
|
393
|
+
const blockIndex = () => blocks.length - 1;
|
|
394
|
+
const toolBlocksByKey = /* @__PURE__ */ new Map();
|
|
395
|
+
const finishCurrentBlock = (block) => {
|
|
396
|
+
if (!block)
|
|
397
|
+
return;
|
|
398
|
+
if (block.type === "text") {
|
|
399
|
+
stream2.push({
|
|
400
|
+
type: "text_end",
|
|
401
|
+
contentIndex: blockIndex(),
|
|
402
|
+
content: block.text,
|
|
403
|
+
partial: output
|
|
404
|
+
});
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (block.type === "thinking") {
|
|
408
|
+
stream2.push({
|
|
409
|
+
type: "thinking_end",
|
|
410
|
+
contentIndex: blockIndex(),
|
|
411
|
+
content: block.thinking,
|
|
412
|
+
partial: output
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
for await (const event of mistralStream) {
|
|
417
|
+
const chunk = event.data;
|
|
418
|
+
output.responseId ||= chunk.id;
|
|
419
|
+
if (chunk.usage) {
|
|
420
|
+
const promptTokens = chunk.usage.prompt_tokens || 0;
|
|
421
|
+
const cachedPromptTokens = getMistralCachedPromptTokens(chunk.usage, promptTokens);
|
|
422
|
+
output.usage.input = Math.max(0, promptTokens - cachedPromptTokens);
|
|
423
|
+
output.usage.output = chunk.usage.completion_tokens || 0;
|
|
424
|
+
output.usage.cacheRead = cachedPromptTokens;
|
|
425
|
+
output.usage.cacheWrite = 0;
|
|
426
|
+
output.usage.totalTokens = chunk.usage.total_tokens || output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
427
|
+
calculateCost(model, output.usage);
|
|
428
|
+
}
|
|
429
|
+
const choice = chunk.choices[0];
|
|
430
|
+
if (!choice)
|
|
431
|
+
continue;
|
|
432
|
+
if (choice.finish_reason) {
|
|
433
|
+
output.rawStopReason = choice.finish_reason;
|
|
434
|
+
const stopReasonResult = mapChatStopReason(choice.finish_reason);
|
|
435
|
+
output.stopReason = stopReasonResult.stopReason;
|
|
436
|
+
if (stopReasonResult.errorMessage) {
|
|
437
|
+
output.errorMessage = stopReasonResult.errorMessage;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
const delta = choice.delta;
|
|
441
|
+
if (delta.content !== null && delta.content !== void 0) {
|
|
442
|
+
const contentItems = typeof delta.content === "string" ? [delta.content] : delta.content;
|
|
443
|
+
for (const item of contentItems) {
|
|
444
|
+
if (typeof item === "string") {
|
|
445
|
+
const textDelta = sanitizeSurrogates(item);
|
|
446
|
+
if (!currentBlock || currentBlock.type !== "text") {
|
|
447
|
+
finishCurrentBlock(currentBlock);
|
|
448
|
+
currentBlock = { type: "text", text: "" };
|
|
449
|
+
output.content.push(currentBlock);
|
|
450
|
+
stream2.push({ type: "text_start", contentIndex: blockIndex(), partial: output });
|
|
451
|
+
}
|
|
452
|
+
currentBlock.text += textDelta;
|
|
453
|
+
stream2.push({
|
|
454
|
+
type: "text_delta",
|
|
455
|
+
contentIndex: blockIndex(),
|
|
456
|
+
delta: textDelta,
|
|
457
|
+
partial: output
|
|
458
|
+
});
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (item.type === "thinking") {
|
|
462
|
+
const deltaText = (item.thinking ?? []).map((part) => part.text ?? "").filter((text) => text.length > 0).join("");
|
|
463
|
+
const thinkingDelta = sanitizeSurrogates(deltaText);
|
|
464
|
+
if (!thinkingDelta)
|
|
465
|
+
continue;
|
|
466
|
+
if (!currentBlock || currentBlock.type !== "thinking") {
|
|
467
|
+
finishCurrentBlock(currentBlock);
|
|
468
|
+
currentBlock = { type: "thinking", thinking: "" };
|
|
469
|
+
output.content.push(currentBlock);
|
|
470
|
+
stream2.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
|
|
471
|
+
}
|
|
472
|
+
currentBlock.thinking += thinkingDelta;
|
|
473
|
+
stream2.push({
|
|
474
|
+
type: "thinking_delta",
|
|
475
|
+
contentIndex: blockIndex(),
|
|
476
|
+
delta: thinkingDelta,
|
|
477
|
+
partial: output
|
|
478
|
+
});
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (item.type === "text") {
|
|
482
|
+
const textDelta = sanitizeSurrogates(item.text ?? "");
|
|
483
|
+
if (!currentBlock || currentBlock.type !== "text") {
|
|
484
|
+
finishCurrentBlock(currentBlock);
|
|
485
|
+
currentBlock = { type: "text", text: "" };
|
|
486
|
+
output.content.push(currentBlock);
|
|
487
|
+
stream2.push({ type: "text_start", contentIndex: blockIndex(), partial: output });
|
|
488
|
+
}
|
|
489
|
+
currentBlock.text += textDelta;
|
|
490
|
+
stream2.push({
|
|
491
|
+
type: "text_delta",
|
|
492
|
+
contentIndex: blockIndex(),
|
|
493
|
+
delta: textDelta,
|
|
494
|
+
partial: output
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const toolCalls = delta.tool_calls || [];
|
|
500
|
+
for (const toolCall of toolCalls) {
|
|
501
|
+
if (currentBlock) {
|
|
502
|
+
finishCurrentBlock(currentBlock);
|
|
503
|
+
currentBlock = null;
|
|
504
|
+
}
|
|
505
|
+
const callId = toolCall.id && toolCall.id !== "null" ? toolCall.id : deriveMistralToolCallId(`toolcall:${toolCall.index ?? 0}`, 0);
|
|
506
|
+
const key = `${callId}:${toolCall.index || 0}`;
|
|
507
|
+
const existingIndex = toolBlocksByKey.get(key);
|
|
508
|
+
let block;
|
|
509
|
+
if (existingIndex !== void 0) {
|
|
510
|
+
const existing = output.content[existingIndex];
|
|
511
|
+
if (existing?.type === "toolCall") {
|
|
512
|
+
block = existing;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (!block) {
|
|
516
|
+
block = {
|
|
517
|
+
type: "toolCall",
|
|
518
|
+
id: callId,
|
|
519
|
+
name: toolCall.function.name,
|
|
520
|
+
arguments: {},
|
|
521
|
+
partialArgs: ""
|
|
522
|
+
};
|
|
523
|
+
output.content.push(block);
|
|
524
|
+
toolBlocksByKey.set(key, output.content.length - 1);
|
|
525
|
+
stream2.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
|
|
526
|
+
}
|
|
527
|
+
const argsDelta = typeof toolCall.function.arguments === "string" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments || {});
|
|
528
|
+
block.partialArgs = (block.partialArgs || "") + argsDelta;
|
|
529
|
+
block.arguments = parseStreamingJson(block.partialArgs);
|
|
530
|
+
stream2.push({
|
|
531
|
+
type: "toolcall_delta",
|
|
532
|
+
contentIndex: toolBlocksByKey.get(key),
|
|
533
|
+
delta: argsDelta,
|
|
534
|
+
partial: output
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
finishCurrentBlock(currentBlock);
|
|
539
|
+
for (const index of toolBlocksByKey.values()) {
|
|
540
|
+
const block = output.content[index];
|
|
541
|
+
if (block.type !== "toolCall")
|
|
542
|
+
continue;
|
|
543
|
+
const toolBlock = block;
|
|
544
|
+
toolBlock.arguments = parseStreamingJson(toolBlock.partialArgs);
|
|
545
|
+
delete toolBlock.partialArgs;
|
|
546
|
+
stream2.push({
|
|
547
|
+
type: "toolcall_end",
|
|
548
|
+
contentIndex: index,
|
|
549
|
+
toolCall: toolBlock,
|
|
550
|
+
partial: output
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
function toFunctionTools(tools) {
|
|
555
|
+
return tools.map((tool) => {
|
|
556
|
+
const strict = resolveJsonSchemaStrictSampling(tool, true);
|
|
557
|
+
return {
|
|
558
|
+
type: "function",
|
|
559
|
+
function: {
|
|
560
|
+
name: tool.name,
|
|
561
|
+
description: tool.description,
|
|
562
|
+
parameters: stripSymbolKeys(getJsonSchemaToolParameters(tool, strict)),
|
|
563
|
+
strict: strict ?? false
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
function stripSymbolKeys(value) {
|
|
569
|
+
if (Array.isArray(value)) {
|
|
570
|
+
return value.map((item) => stripSymbolKeys(item));
|
|
571
|
+
}
|
|
572
|
+
if (value && typeof value === "object") {
|
|
573
|
+
const result = {};
|
|
574
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
575
|
+
result[key] = stripSymbolKeys(entry);
|
|
576
|
+
}
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
return value;
|
|
580
|
+
}
|
|
581
|
+
function toChatMessages(messages, supportsImages) {
|
|
582
|
+
const result = [];
|
|
583
|
+
for (const msg of messages) {
|
|
584
|
+
if (msg.role === "user") {
|
|
585
|
+
if (typeof msg.content === "string") {
|
|
586
|
+
result.push({ role: "user", content: sanitizeSurrogates(msg.content) });
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
const hadImages = msg.content.some((item) => item.type === "image");
|
|
590
|
+
const content = msg.content.filter((item) => item.type === "text" || supportsImages).map((item) => {
|
|
591
|
+
if (item.type === "text")
|
|
592
|
+
return { type: "text", text: sanitizeSurrogates(item.text) };
|
|
593
|
+
return { type: "image_url", imageUrl: `data:${item.mimeType};base64,${item.data}` };
|
|
594
|
+
});
|
|
595
|
+
if (content.length > 0) {
|
|
596
|
+
result.push({ role: "user", content });
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
if (hadImages && !supportsImages) {
|
|
600
|
+
result.push({ role: "user", content: "(image omitted: model does not support images)" });
|
|
601
|
+
}
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (msg.role === "assistant") {
|
|
605
|
+
const contentParts = [];
|
|
606
|
+
const toolCalls = [];
|
|
607
|
+
for (const block of msg.content) {
|
|
608
|
+
if (block.type === "text") {
|
|
609
|
+
if (block.text.trim().length > 0) {
|
|
610
|
+
contentParts.push({ type: "text", text: sanitizeSurrogates(block.text) });
|
|
611
|
+
}
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (block.type === "thinking") {
|
|
615
|
+
if (block.thinking.trim().length > 0) {
|
|
616
|
+
contentParts.push({
|
|
617
|
+
type: "thinking",
|
|
618
|
+
thinking: [{ type: "text", text: sanitizeSurrogates(block.thinking) }]
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
toolCalls.push({
|
|
624
|
+
id: block.id,
|
|
625
|
+
type: "function",
|
|
626
|
+
function: { name: block.name, arguments: JSON.stringify(block.arguments || {}) },
|
|
627
|
+
index: 0
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
const assistantMessage = { role: "assistant", prefix: false };
|
|
631
|
+
if (contentParts.length > 0)
|
|
632
|
+
assistantMessage.content = contentParts;
|
|
633
|
+
if (toolCalls.length > 0)
|
|
634
|
+
assistantMessage.toolCalls = toolCalls;
|
|
635
|
+
if (contentParts.length > 0 || toolCalls.length > 0)
|
|
636
|
+
result.push(assistantMessage);
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
const toolContent = [];
|
|
640
|
+
const textResult = msg.content.filter((part) => part.type === "text").map((part) => part.type === "text" ? sanitizeSurrogates(part.text) : "").join("\n");
|
|
641
|
+
const hasImages = msg.content.some((part) => part.type === "image");
|
|
642
|
+
const toolText = buildToolResultText(textResult, hasImages, supportsImages, msg.isError);
|
|
643
|
+
toolContent.push({ type: "text", text: toolText });
|
|
644
|
+
for (const part of msg.content) {
|
|
645
|
+
if (!supportsImages)
|
|
646
|
+
continue;
|
|
647
|
+
if (part.type !== "image")
|
|
648
|
+
continue;
|
|
649
|
+
toolContent.push({
|
|
650
|
+
type: "image_url",
|
|
651
|
+
imageUrl: `data:${part.mimeType};base64,${part.data}`
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
result.push({
|
|
655
|
+
role: "tool",
|
|
656
|
+
toolCallId: msg.toolCallId,
|
|
657
|
+
name: msg.toolName,
|
|
658
|
+
content: toolContent
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
function buildToolResultText(text, hasImages, supportsImages, isError) {
|
|
664
|
+
const trimmed = text.trim();
|
|
665
|
+
const errorPrefix = isError ? "[tool error] " : "";
|
|
666
|
+
if (trimmed.length > 0) {
|
|
667
|
+
const imageSuffix = hasImages && !supportsImages ? "\n[tool image omitted: model does not support images]" : "";
|
|
668
|
+
return `${errorPrefix}${trimmed}${imageSuffix}`;
|
|
669
|
+
}
|
|
670
|
+
if (hasImages) {
|
|
671
|
+
if (supportsImages) {
|
|
672
|
+
return isError ? "[tool error] (see attached image)" : "(see attached image)";
|
|
673
|
+
}
|
|
674
|
+
return isError ? "[tool error] (image omitted: model does not support images)" : "(image omitted: model does not support images)";
|
|
675
|
+
}
|
|
676
|
+
return isError ? "[tool error] (no tool output)" : "(no tool output)";
|
|
677
|
+
}
|
|
678
|
+
function usesReasoningEffort(model) {
|
|
679
|
+
return model.id === "mistral-small-2603" || model.id === "mistral-small-latest" || model.id === "mistral-medium-3.5";
|
|
680
|
+
}
|
|
681
|
+
function usesPromptModeReasoning(model) {
|
|
682
|
+
return model.reasoning && !usesReasoningEffort(model);
|
|
683
|
+
}
|
|
684
|
+
function mapReasoningEffort(model, level) {
|
|
685
|
+
return model.thinkingLevelMap?.[level] ?? "high";
|
|
686
|
+
}
|
|
687
|
+
function mapToolChoice(choice) {
|
|
688
|
+
if (!choice)
|
|
689
|
+
return void 0;
|
|
690
|
+
if (choice === "auto" || choice === "none" || choice === "any" || choice === "required") {
|
|
691
|
+
return choice;
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
type: "function",
|
|
695
|
+
function: { name: choice.function.name }
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
function mapChatStopReason(reason) {
|
|
699
|
+
if (reason === null)
|
|
700
|
+
return { stopReason: "stop" };
|
|
701
|
+
switch (reason) {
|
|
702
|
+
case "stop":
|
|
703
|
+
return { stopReason: "stop" };
|
|
704
|
+
case "length":
|
|
705
|
+
case "model_length":
|
|
706
|
+
return { stopReason: "length" };
|
|
707
|
+
case "tool_calls":
|
|
708
|
+
return { stopReason: "toolUse" };
|
|
709
|
+
case "error":
|
|
710
|
+
return { stopReason: "error", errorMessage: "Provider stopped with: error" };
|
|
711
|
+
default:
|
|
712
|
+
return { stopReason: "error", errorMessage: `Provider stopped with: ${reason}` };
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
export {
|
|
716
|
+
stream,
|
|
717
|
+
streamSimple
|
|
718
|
+
};
|