@openclaw/ai 2026.7.2-beta.7 → 2026.8.1-beta.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/{anthropic-CH4UUnZr.mjs → anthropic-B6dLpq5L.mjs} +55 -203
- package/dist/{src-QkygScBs.mjs → anthropic-JsNA5KCu.mjs} +0 -1
- package/dist/anthropic-compaction-replay-8lJNKXOE.mjs +840 -0
- package/dist/anthropic-payload-policy-CiEuQS72.d.mts +49 -0
- package/dist/{api-registry-DlMgPR39.d.mts → api-registry-k3zTz0cV.d.mts} +1 -1
- package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-mxIOtUnn.mjs} +23 -29
- package/dist/diagnostics.d.mts +24 -1
- package/dist/diagnostics.mjs +2 -1
- package/dist/{event-stream-YjaPW20U.d.mts → event-stream-BP6AWT8j.d.mts} +4 -1
- package/dist/{event-stream-D8n2uFee.mjs → event-stream-uSMZJ3FA.mjs} +26 -5
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{google-CtSg0iTS.mjs → google-C7h2QzDX.mjs} +5 -5
- package/dist/{google-shared-DNBz5rcD.mjs → google-shared-B0Qr9OR7.mjs} +146 -89
- package/dist/google-thinking-level-C-V3tecN.mjs +9 -0
- package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-Bhc3TjDl.mjs} +11 -7
- package/dist/{llm-request-activity-BjtkplhG.mjs → headers-DdOQtGuU.mjs} +9 -1
- package/dist/host-DTqNc7ad.mjs +466 -0
- package/dist/{host-B9GUmcra.d.mts → host-vWgMMhiJ.d.mts} +9 -4
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -5
- package/dist/internal/anthropic.d.mts +29 -5
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -0
- package/dist/internal/openai-responses-payload-policy.mjs +3 -0
- package/dist/internal/openai.d.mts +6 -6
- package/dist/internal/openai.mjs +8 -7
- package/dist/internal/runtime.d.mts +17 -5
- package/dist/internal/runtime.mjs +85 -73
- package/dist/internal/shared.d.mts +1 -6
- package/dist/internal/shared.mjs +3 -5
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-CDnesDM_.mjs} +4 -6
- package/dist/{mistral-CWmpvWYh.mjs → mistral-CEWoQI_g.mjs} +45 -48
- package/dist/number-coercion-H9qHik3g.mjs +71 -0
- package/dist/openai-chatgpt-jwt-KWcgd0d_.mjs +19 -0
- package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-CrPmqERt.mjs} +284 -240
- package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-BPnt4Sml.mjs} +65 -99
- package/dist/{openai-completions-compat-DBWjXoMZ.d.mts → openai-completions-compat-Dt3dcawL.d.mts} +2 -2
- package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-DhIKtOup.mjs} +18 -41
- package/dist/openai-responses-contracts-CyfIkQi5.mjs +253 -0
- package/dist/openai-responses-contracts-XpZJxrRG.d.mts +68 -0
- package/dist/openai-responses-payload-policy-BDxV-W0c.mjs +206 -0
- package/dist/openai-responses-payload-policy-BSs371VM.d.mts +40 -0
- package/dist/openai-responses-prompt-observer-internal-DgNTYnRY.mjs +46 -0
- package/dist/{openai-responses-stream-internal-Cw5txaGW.mjs → openai-responses-shared-DXIt3iY5.mjs} +1406 -940
- package/dist/{openai-reasoning-compat-YgeLncHw.mjs → openai-stop-reason-BkFkqqK0.mjs} +204 -37
- package/dist/openai-tool-projection-CY04OcvQ.mjs +338 -0
- package/dist/provider-error-BUwEnjXq.mjs +429 -0
- package/dist/provider-error-CzNw4BWX.d.mts +12 -0
- package/dist/{provider-options-D8bB3z9b.d.mts → provider-options-B96RdNpH.d.mts} +9 -3
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +155 -0
- package/dist/provider-types.d.mts +31 -0
- package/dist/provider-types.mjs +8 -0
- package/dist/providers.d.mts +1 -1
- package/dist/providers.mjs +17 -19
- package/dist/{reasoning-tag-text-partitioner-CGDyLWUR.mjs → reasoning-tag-text-partitioner-rnPwX2pg.mjs} +14 -8
- package/dist/record-coerce-DdXsgUd_.mjs +23 -0
- package/dist/sanitize-unicode-BYqrYtC_.mjs +90 -0
- package/dist/session-resources-CkR4WWy1.mjs +21 -0
- package/dist/simple-options-D58D5Kvw.mjs +117 -0
- package/dist/src-D2H6yKkH.mjs +2 -0
- package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-MK28puvq.mjs} +2 -2
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{tool-schema-json-projection-BwNu3nDi.mjs → tool-schema-json-projection-q5d7QX5c.mjs} +32 -7
- package/dist/transport-utils-DJqkxbhC.mjs +138 -0
- package/dist/transports.d.mts +166 -241
- package/dist/transports.mjs +1979 -1825
- package/dist/types-BDdaOVi2.mjs +6 -0
- package/dist/{types-bzp5k29J.d.mts → types-BHNrPS1l.d.mts} +23 -1
- package/dist/types.d.mts +4 -4
- package/dist/types.mjs +6 -4
- package/dist/utf16-slice-CvGodqok.mjs +29 -0
- package/dist/{validation-DAa_yFOM.mjs → validation-B61OhAio.mjs} +6 -6
- package/dist/{validation-B-j7cOYp.d.mts → validation-DT9SrFn3.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +15 -1
- package/dist/anthropic-usage-DWU-x8MI.mjs +0 -459
- package/dist/error-coercion-DgxlWC0n.mjs +0 -15
- package/dist/headers-B_e4-1J0.mjs +0 -9
- package/dist/host-Dog2WQiR.mjs +0 -369
- package/dist/number-coercion-DvG7SNMg.mjs +0 -129
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +0 -39
- package/dist/openai-responses-shared-pXl6Wd8S.mjs +0 -392
- package/dist/openai-tool-projection-OhX64DoP.mjs +0 -215
- package/dist/provider-error-CAEvRjry.mjs +0 -47
- package/dist/sanitize-unicode-DT5o51ur.mjs +0 -26
- package/dist/simple-options-9lhRrN73.mjs +0 -50
- package/dist/tool-result-text-CTpIRbYd.mjs +0 -225
- package/dist/transform-messages-C8mBqZxF.mjs +0 -2
- package/dist/transport-stream-shared-D81p90xq.mjs +0 -297
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
import { i as transformMessages, n as getAiTransportHost } from "./host-Dog2WQiR.mjs";
|
|
2
|
-
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
3
|
-
import { a as isImageWithMediaPayload, d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName, r as extractToolResultText, t as describeToolResultMediaPlaceholder } from "./tool-result-text-CTpIRbYd.mjs";
|
|
4
|
-
import { t as projectOpenAITools } from "./openai-tool-projection-OhX64DoP.mjs";
|
|
5
|
-
import { l as clampThinkingLevel } from "./number-coercion-DvG7SNMg.mjs";
|
|
6
|
-
import { d as transportAbortError } from "./transport-stream-shared-D81p90xq.mjs";
|
|
7
|
-
import { Y as normalizeOpenAIStrictToolParameters, Z as resolveOpenAIProjectedToolsStrictToolFlag, _t as supportsOpenAITemperature, gt as supportsOpenAIReasoningEffort, mt as resolveOpenAIReasoningEffortForModel, n as processResponsesStream, q as findOpenAIStrictToolProjectionDiagnostics } from "./openai-responses-stream-internal-Cw5txaGW.mjs";
|
|
8
|
-
import { i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BBys9hSb.mjs";
|
|
9
|
-
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
10
|
-
import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
|
|
11
|
-
import "./transform-messages-C8mBqZxF.mjs";
|
|
12
|
-
import { createHash } from "node:crypto";
|
|
13
|
-
//#region packages/ai/src/providers/openai-responses-tools.ts
|
|
14
|
-
const LOG_SUBSYSTEM = "llm/openai-responses";
|
|
15
|
-
const MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 64;
|
|
16
|
-
const loggedStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
|
|
17
|
-
/** Converts and returns the projection used to reconcile tool choices. */
|
|
18
|
-
function convertResponsesToolPayload(tools, options) {
|
|
19
|
-
const projection = projectOpenAITools(tools);
|
|
20
|
-
const strict = resolveResponsesStrictToolFlag(projection, resolveResponsesStrictToolSetting(options), options?.model);
|
|
21
|
-
return {
|
|
22
|
-
projection,
|
|
23
|
-
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
24
|
-
const result = {
|
|
25
|
-
type: "function",
|
|
26
|
-
name: tool.name,
|
|
27
|
-
description: tool.description,
|
|
28
|
-
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, options?.model?.compat)
|
|
29
|
-
};
|
|
30
|
-
if (strict !== void 0) result.strict = strict;
|
|
31
|
-
return result;
|
|
32
|
-
})
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function resolveResponsesStrictToolSetting(options) {
|
|
36
|
-
if (options?.strict !== void 0) return options.strict;
|
|
37
|
-
if (options?.model) return getAiTransportHost().resolveOpenAIStrictToolSetting(options.model, {
|
|
38
|
-
transport: "stream",
|
|
39
|
-
supportsStrictMode: options.supportsStrictMode
|
|
40
|
-
});
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
function resolveResponsesStrictToolFlag(projection, strictSetting, model) {
|
|
44
|
-
const strict = resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
|
|
45
|
-
if (strictSetting === true && strict === false && model) getAiTransportHost().logDebug(LOG_SUBSYSTEM, () => {
|
|
46
|
-
const diagnostics = findOpenAIStrictToolProjectionDiagnostics(projection);
|
|
47
|
-
if (!shouldLogStrictToolDowngradeDiagnostic(diagnostics, model)) return null;
|
|
48
|
-
const sample = diagnostics.slice(0, 5).map((entry) => ({
|
|
49
|
-
tool: entry.toolName ?? `tool[${entry.toolIndex}]`,
|
|
50
|
-
violations: entry.violations.slice(0, 8)
|
|
51
|
-
}));
|
|
52
|
-
return {
|
|
53
|
-
message: `OpenAI responses tool schema strict mode downgraded to strict=false for ${model.provider ?? "unknown"}/${model.id ?? "unknown"} because ${diagnostics.length} tool schema(s) are not strict-compatible`,
|
|
54
|
-
data: {
|
|
55
|
-
provider: model.provider,
|
|
56
|
-
model: model.id,
|
|
57
|
-
incompatibleToolCount: diagnostics.length,
|
|
58
|
-
sample
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
return strict;
|
|
63
|
-
}
|
|
64
|
-
function shouldLogStrictToolDowngradeDiagnostic(diagnostics, model) {
|
|
65
|
-
const key = createHash("sha256").update(JSON.stringify({
|
|
66
|
-
provider: model.provider,
|
|
67
|
-
model: model.id,
|
|
68
|
-
diagnostics: diagnostics.map((entry) => ({
|
|
69
|
-
toolIndex: entry.toolIndex,
|
|
70
|
-
toolName: entry.toolName ?? null,
|
|
71
|
-
violations: entry.violations
|
|
72
|
-
}))
|
|
73
|
-
})).digest("hex");
|
|
74
|
-
if (loggedStrictToolDowngradeDiagnosticKeys.has(key)) return false;
|
|
75
|
-
if (loggedStrictToolDowngradeDiagnosticKeys.size >= MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS) loggedStrictToolDowngradeDiagnosticKeys.clear();
|
|
76
|
-
loggedStrictToolDowngradeDiagnosticKeys.add(key);
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region packages/ai/src/providers/openai-responses-shared.ts
|
|
81
|
-
const EMPTY_TOOL_RESULT_TEXT = "(no output)";
|
|
82
|
-
function splitResponsesToolCallId(id) {
|
|
83
|
-
const separatorIndex = id.indexOf("|");
|
|
84
|
-
return separatorIndex === -1 ? [id, void 0] : [id.slice(0, separatorIndex), id.slice(separatorIndex + 1)];
|
|
85
|
-
}
|
|
86
|
-
function sanitizeToolResultText(text, fallback) {
|
|
87
|
-
const sanitized = sanitizeSurrogates(text);
|
|
88
|
-
return sanitized.trim().length > 0 ? sanitized : fallback;
|
|
89
|
-
}
|
|
90
|
-
function normalizeResponsesReasoningReplayItem(params) {
|
|
91
|
-
const next = { ...params.item };
|
|
92
|
-
if (!Array.isArray(next.summary)) next.summary = [];
|
|
93
|
-
if (!params.replayResponsesItemIds) delete next.id;
|
|
94
|
-
return next;
|
|
95
|
-
}
|
|
96
|
-
function parseTextSignature(signature) {
|
|
97
|
-
if (!signature) return;
|
|
98
|
-
if (signature.startsWith("{")) try {
|
|
99
|
-
const parsed = JSON.parse(signature);
|
|
100
|
-
if (parsed.v === 1) {
|
|
101
|
-
const id = typeof parsed.id === "string" ? parsed.id : void 0;
|
|
102
|
-
const phase = parsed.phase === "commentary" || parsed.phase === "final_answer" ? parsed.phase : void 0;
|
|
103
|
-
if (id !== void 0 || phase !== void 0) return {
|
|
104
|
-
id,
|
|
105
|
-
phase
|
|
106
|
-
};
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
} catch {}
|
|
110
|
-
return { id: signature };
|
|
111
|
-
}
|
|
112
|
-
function resolveReplayableResponsesMessageId(params) {
|
|
113
|
-
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
114
|
-
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
115
|
-
}
|
|
116
|
-
function isResponsesReasoningEffort(effort) {
|
|
117
|
-
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max";
|
|
118
|
-
}
|
|
119
|
-
function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
120
|
-
const messages = [];
|
|
121
|
-
const shouldReplayResponsesItemIds = options?.replayResponsesItemIds ?? true;
|
|
122
|
-
const normalizeIdPart = (part) => {
|
|
123
|
-
const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
124
|
-
return (sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized).replace(/_+$/, "");
|
|
125
|
-
};
|
|
126
|
-
const buildForeignResponsesItemId = (itemId) => {
|
|
127
|
-
const normalized = `fc_${shortHash(itemId)}`;
|
|
128
|
-
return normalized.length > 64 ? normalized.slice(0, 64) : normalized;
|
|
129
|
-
};
|
|
130
|
-
const normalizeToolCallId = (id, targetModel, source) => {
|
|
131
|
-
if (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id);
|
|
132
|
-
if (!id.includes("|")) return normalizeIdPart(id);
|
|
133
|
-
const [callId, itemId = ""] = splitResponsesToolCallId(id);
|
|
134
|
-
const normalizedCallId = normalizeIdPart(callId);
|
|
135
|
-
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
136
|
-
if (!normalizedItemId.startsWith("fc_")) normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);
|
|
137
|
-
return `${normalizedCallId}|${normalizedItemId}`;
|
|
138
|
-
};
|
|
139
|
-
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
140
|
-
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) {
|
|
141
|
-
const compat = model.compat;
|
|
142
|
-
const role = model.reasoning && compat?.supportsDeveloperRole !== false ? "developer" : "system";
|
|
143
|
-
messages.push({
|
|
144
|
-
type: "message",
|
|
145
|
-
role,
|
|
146
|
-
content: [{
|
|
147
|
-
type: "input_text",
|
|
148
|
-
text: sanitizeSurrogates(stripSystemPromptCacheBoundary(context.systemPrompt))
|
|
149
|
-
}]
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
let msgIndex = 0;
|
|
153
|
-
for (const msg of transformedMessages) {
|
|
154
|
-
if (msg.role === "user") if (typeof msg.content === "string") messages.push({
|
|
155
|
-
type: "message",
|
|
156
|
-
role: "user",
|
|
157
|
-
content: [{
|
|
158
|
-
type: "input_text",
|
|
159
|
-
text: sanitizeSurrogates(msg.content)
|
|
160
|
-
}]
|
|
161
|
-
});
|
|
162
|
-
else {
|
|
163
|
-
const content = msg.content.map((item) => {
|
|
164
|
-
if (item.type === "text") return {
|
|
165
|
-
type: "input_text",
|
|
166
|
-
text: sanitizeSurrogates(item.text)
|
|
167
|
-
};
|
|
168
|
-
return {
|
|
169
|
-
type: "input_image",
|
|
170
|
-
detail: "auto",
|
|
171
|
-
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
172
|
-
};
|
|
173
|
-
});
|
|
174
|
-
if (content.length === 0) continue;
|
|
175
|
-
messages.push({
|
|
176
|
-
type: "message",
|
|
177
|
-
role: "user",
|
|
178
|
-
content
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
else if (msg.role === "assistant") {
|
|
182
|
-
const output = [];
|
|
183
|
-
let textFallbackOrdinal = 0;
|
|
184
|
-
const assistantMsg = msg;
|
|
185
|
-
let previousReplayItemWasReasoning = false;
|
|
186
|
-
const isDifferentModel = assistantMsg.model !== model.id && assistantMsg.provider === model.provider && assistantMsg.api === model.api;
|
|
187
|
-
for (const block of msg.content) if (block.type === "thinking") {
|
|
188
|
-
if (block.thinkingSignature) {
|
|
189
|
-
const reasoningItem = normalizeResponsesReasoningReplayItem({
|
|
190
|
-
item: JSON.parse(block.thinkingSignature),
|
|
191
|
-
replayResponsesItemIds: shouldReplayResponsesItemIds
|
|
192
|
-
});
|
|
193
|
-
output.push(reasoningItem);
|
|
194
|
-
previousReplayItemWasReasoning = true;
|
|
195
|
-
}
|
|
196
|
-
} else if (block.type === "text") {
|
|
197
|
-
const textBlock = block;
|
|
198
|
-
const parsedSignature = parseTextSignature(textBlock.textSignature);
|
|
199
|
-
let msgId = shouldReplayResponsesItemIds ? resolveReplayableResponsesMessageId({
|
|
200
|
-
textSignatureId: parsedSignature?.id,
|
|
201
|
-
fallbackId: `msg_${msgIndex}`,
|
|
202
|
-
fallbackOrdinal: textFallbackOrdinal,
|
|
203
|
-
previousReplayItemWasReasoning
|
|
204
|
-
}) : void 0;
|
|
205
|
-
if (!parsedSignature?.id) textFallbackOrdinal += 1;
|
|
206
|
-
if (msgId && msgId.length > 64) msgId = `msg_${shortHash(msgId)}`;
|
|
207
|
-
const messageItem = {
|
|
208
|
-
type: "message",
|
|
209
|
-
role: "assistant",
|
|
210
|
-
content: [{
|
|
211
|
-
type: "output_text",
|
|
212
|
-
text: sanitizeSurrogates(textBlock.text),
|
|
213
|
-
annotations: []
|
|
214
|
-
}],
|
|
215
|
-
status: "completed",
|
|
216
|
-
...msgId ? { id: msgId } : {},
|
|
217
|
-
phase: parsedSignature?.phase
|
|
218
|
-
};
|
|
219
|
-
output.push(messageItem);
|
|
220
|
-
previousReplayItemWasReasoning = false;
|
|
221
|
-
} else if (block.type === "toolCall") {
|
|
222
|
-
const toolCall = block;
|
|
223
|
-
const [callId, itemIdRaw] = splitResponsesToolCallId(toolCall.id);
|
|
224
|
-
let itemId = shouldReplayResponsesItemIds ? itemIdRaw : void 0;
|
|
225
|
-
if (shouldReplayResponsesItemIds && isDifferentModel && itemId?.startsWith("fc_")) itemId = void 0;
|
|
226
|
-
output.push({
|
|
227
|
-
type: "function_call",
|
|
228
|
-
...itemId ? { id: itemId } : {},
|
|
229
|
-
call_id: callId,
|
|
230
|
-
name: toolCall.name,
|
|
231
|
-
arguments: JSON.stringify(toolCall.arguments)
|
|
232
|
-
});
|
|
233
|
-
previousReplayItemWasReasoning = false;
|
|
234
|
-
}
|
|
235
|
-
if (output.length === 0) continue;
|
|
236
|
-
messages.push(...output);
|
|
237
|
-
} else if (msg.role === "toolResult") {
|
|
238
|
-
const textResult = extractToolResultText(msg.content);
|
|
239
|
-
const sanitizedTextResult = sanitizeSurrogates(textResult);
|
|
240
|
-
const hasImages = msg.content.some(isImageWithMediaPayload);
|
|
241
|
-
const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
|
|
242
|
-
const hasText = sanitizedTextResult.trim().length > 0;
|
|
243
|
-
const [callId] = splitResponsesToolCallId(msg.toolCallId);
|
|
244
|
-
let output;
|
|
245
|
-
if (hasImages && model.input.includes("image")) {
|
|
246
|
-
const contentParts = [];
|
|
247
|
-
if (hasText) contentParts.push({
|
|
248
|
-
type: "input_text",
|
|
249
|
-
text: sanitizedTextResult
|
|
250
|
-
});
|
|
251
|
-
else if (mediaPlaceholder === "(see attached media)") contentParts.push({
|
|
252
|
-
type: "input_text",
|
|
253
|
-
text: mediaPlaceholder
|
|
254
|
-
});
|
|
255
|
-
for (const block of msg.content) if (isImageWithMediaPayload(block)) contentParts.push({
|
|
256
|
-
type: "input_image",
|
|
257
|
-
detail: "auto",
|
|
258
|
-
image_url: `data:${block.mimeType};base64,${block.data}`
|
|
259
|
-
});
|
|
260
|
-
output = contentParts;
|
|
261
|
-
} else output = sanitizeToolResultText(textResult, mediaPlaceholder ?? EMPTY_TOOL_RESULT_TEXT);
|
|
262
|
-
messages.push({
|
|
263
|
-
type: "function_call_output",
|
|
264
|
-
call_id: callId,
|
|
265
|
-
output
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
msgIndex++;
|
|
269
|
-
}
|
|
270
|
-
return messages;
|
|
271
|
-
}
|
|
272
|
-
function createResponsesAssistantOutput(model, api = model.api) {
|
|
273
|
-
return {
|
|
274
|
-
role: "assistant",
|
|
275
|
-
content: [],
|
|
276
|
-
api,
|
|
277
|
-
provider: model.provider,
|
|
278
|
-
model: model.id,
|
|
279
|
-
usage: {
|
|
280
|
-
input: 0,
|
|
281
|
-
output: 0,
|
|
282
|
-
cacheRead: 0,
|
|
283
|
-
cacheWrite: 0,
|
|
284
|
-
totalTokens: 0,
|
|
285
|
-
cost: {
|
|
286
|
-
input: 0,
|
|
287
|
-
output: 0,
|
|
288
|
-
cacheRead: 0,
|
|
289
|
-
cacheWrite: 0,
|
|
290
|
-
total: 0
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
stopReason: "stop",
|
|
294
|
-
timestamp: Date.now()
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
function resolveResponsesReasoningEffort(model, reasoning) {
|
|
298
|
-
const clampedReasoning = reasoning ? clampThinkingLevel(model, reasoning) : void 0;
|
|
299
|
-
if (!clampedReasoning || clampedReasoning === "off") return;
|
|
300
|
-
if (clampedReasoning === "max") return supportsOpenAIReasoningEffort(model, "max") ? "max" : "xhigh";
|
|
301
|
-
if (clampedReasoning === "minimal" && model.provider === "openai" && supportsOpenAIReasoningEffort(model, "max")) {
|
|
302
|
-
const effort = resolveOpenAIReasoningEffortForModel({
|
|
303
|
-
model,
|
|
304
|
-
effort: "minimal"
|
|
305
|
-
});
|
|
306
|
-
return isResponsesReasoningEffort(effort) ? effort : void 0;
|
|
307
|
-
}
|
|
308
|
-
return clampedReasoning;
|
|
309
|
-
}
|
|
310
|
-
function applyCommonResponsesParams(params, model, context, options, config) {
|
|
311
|
-
if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
|
|
312
|
-
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
|
|
313
|
-
if (context.tools) {
|
|
314
|
-
const converted = convertResponsesToolPayload(context.tools, { model });
|
|
315
|
-
if (converted.tools.length > 0) params.tools = converted.tools;
|
|
316
|
-
}
|
|
317
|
-
if (!model.reasoning) return;
|
|
318
|
-
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
319
|
-
params.reasoning = {
|
|
320
|
-
effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
|
|
321
|
-
summary: options?.reasoningSummary || "auto"
|
|
322
|
-
};
|
|
323
|
-
params.include = ["reasoning.encrypted_content"];
|
|
324
|
-
} else if ((config?.setDefaultReasoningOff ?? true) && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
|
|
325
|
-
}
|
|
326
|
-
function buildResponsesRequestOptions(options) {
|
|
327
|
-
return {
|
|
328
|
-
...options?.signal ? { signal: options.signal } : {},
|
|
329
|
-
...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
|
|
330
|
-
maxRetries: options?.maxRetries ?? 0
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
function cleanStreamingScratchBuffers(output) {
|
|
334
|
-
for (const block of output.content) {
|
|
335
|
-
delete block.index;
|
|
336
|
-
delete block.partialJson;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
async function runResponsesStreamLifecycle(params) {
|
|
340
|
-
const { stream, model, output, options } = params;
|
|
341
|
-
let firstEventAbort;
|
|
342
|
-
try {
|
|
343
|
-
const client = params.createClient();
|
|
344
|
-
let requestParams = params.buildParams();
|
|
345
|
-
const nextParams = await options?.onPayload?.(requestParams, model);
|
|
346
|
-
if (nextParams !== void 0) requestParams = nextParams;
|
|
347
|
-
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
348
|
-
const { data: openaiStream, response } = await client.responses.create(requestParams, {
|
|
349
|
-
...buildResponsesRequestOptions(options),
|
|
350
|
-
signal: firstEventAbort.signal
|
|
351
|
-
}).withResponse();
|
|
352
|
-
await options?.onResponse?.({
|
|
353
|
-
status: response.status,
|
|
354
|
-
headers: headersToRecord(response.headers)
|
|
355
|
-
}, model);
|
|
356
|
-
stream.push({
|
|
357
|
-
type: "start",
|
|
358
|
-
partial: output
|
|
359
|
-
});
|
|
360
|
-
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
361
|
-
const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
|
|
362
|
-
await processResponsesStream(openaiStream, output, stream, model, params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
|
|
363
|
-
...params.processStreamOptions,
|
|
364
|
-
firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
|
|
365
|
-
abortFirstEventStream: params.processStreamOptions?.abortFirstEventStream ?? firstEventAbort.abort,
|
|
366
|
-
onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
|
|
367
|
-
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
368
|
-
} : void 0);
|
|
369
|
-
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
370
|
-
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
371
|
-
stream.push({
|
|
372
|
-
type: "done",
|
|
373
|
-
reason: output.stopReason,
|
|
374
|
-
message: output
|
|
375
|
-
});
|
|
376
|
-
stream.end();
|
|
377
|
-
} catch (error) {
|
|
378
|
-
cleanStreamingScratchBuffers(output);
|
|
379
|
-
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
380
|
-
output.errorMessage = params.formatError(error);
|
|
381
|
-
stream.push({
|
|
382
|
-
type: "error",
|
|
383
|
-
reason: output.stopReason,
|
|
384
|
-
error: output
|
|
385
|
-
});
|
|
386
|
-
stream.end();
|
|
387
|
-
} finally {
|
|
388
|
-
firstEventAbort?.dispose();
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
//#endregion
|
|
392
|
-
export { runResponsesStreamLifecycle as a, resolveResponsesReasoningEffort as i, convertResponsesMessages as n, convertResponsesToolPayload as o, createResponsesAssistantOutput as r, applyCommonResponsesParams as t };
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import { g as isRecord, n as getAiTransportHost } from "./host-Dog2WQiR.mjs";
|
|
2
|
-
import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-BwNu3nDi.mjs";
|
|
3
|
-
//#region packages/ai/src/transports/host-policy.ts
|
|
4
|
-
function buildGuardedModelFetch(model, timeoutMs, options) {
|
|
5
|
-
const host = getAiTransportHost();
|
|
6
|
-
if (options !== void 0) return host.buildModelFetch(model, timeoutMs, options) ?? globalThis.fetch;
|
|
7
|
-
if (timeoutMs !== void 0) return host.buildModelFetch(model, timeoutMs) ?? globalThis.fetch;
|
|
8
|
-
return host.buildModelFetch(model) ?? globalThis.fetch;
|
|
9
|
-
}
|
|
10
|
-
function resolveProviderEndpoint(baseUrl) {
|
|
11
|
-
return { endpointClass: getAiTransportHost().resolveProviderEndpointClass(baseUrl) };
|
|
12
|
-
}
|
|
13
|
-
function resolveProviderRequestCapabilities(input) {
|
|
14
|
-
return getAiTransportHost().resolveProviderRequestCapabilities(input);
|
|
15
|
-
}
|
|
16
|
-
function resolveProviderRequestPolicyConfig(input) {
|
|
17
|
-
return { headers: getAiTransportHost().resolveProviderRequestHeaders(input) };
|
|
18
|
-
}
|
|
19
|
-
function resolveModelRequestTimeoutMs(model, timeoutMs) {
|
|
20
|
-
return timeoutMs ?? getAiTransportHost().resolveModelRequestTimeoutMs(model);
|
|
21
|
-
}
|
|
22
|
-
function resolveOpenAIStrictToolSetting(model, options) {
|
|
23
|
-
return getAiTransportHost().resolveOpenAIStrictToolSetting(model, options);
|
|
24
|
-
}
|
|
25
|
-
function transformTransportMessages(messages, model, normalizeToolCallId, options) {
|
|
26
|
-
return getAiTransportHost().transformTransportMessages(messages, model, normalizeToolCallId, options);
|
|
27
|
-
}
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region packages/ai/src/providers/openai-tool-projection.ts
|
|
30
|
-
function unreadableToolDiagnostic(toolIndex) {
|
|
31
|
-
return {
|
|
32
|
-
toolIndex,
|
|
33
|
-
violations: [`tool[${toolIndex}] is unreadable`]
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/** Snapshots direct/custom tool descriptors before OpenAI payload construction. */
|
|
37
|
-
function projectOpenAITools(tools) {
|
|
38
|
-
let inputToolCount;
|
|
39
|
-
try {
|
|
40
|
-
inputToolCount = tools.length;
|
|
41
|
-
} catch {
|
|
42
|
-
return {
|
|
43
|
-
inputToolCount: 0,
|
|
44
|
-
tools: [],
|
|
45
|
-
diagnostics: [unreadableToolDiagnostic(0)]
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
const projectedTools = [];
|
|
49
|
-
const diagnostics = [];
|
|
50
|
-
for (let toolIndex = 0; toolIndex < inputToolCount; toolIndex += 1) {
|
|
51
|
-
let tool;
|
|
52
|
-
try {
|
|
53
|
-
const candidate = tools[toolIndex];
|
|
54
|
-
if (!candidate) {
|
|
55
|
-
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
tool = candidate;
|
|
59
|
-
} catch {
|
|
60
|
-
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
let name;
|
|
64
|
-
try {
|
|
65
|
-
name = tool.name;
|
|
66
|
-
} catch {
|
|
67
|
-
diagnostics.push({
|
|
68
|
-
toolIndex,
|
|
69
|
-
violations: [`tool[${toolIndex}].name is unreadable`]
|
|
70
|
-
});
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (typeof name !== "string" || !name) {
|
|
74
|
-
diagnostics.push({
|
|
75
|
-
toolIndex,
|
|
76
|
-
violations: [`tool[${toolIndex}].name is empty`]
|
|
77
|
-
});
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
let parameters;
|
|
81
|
-
try {
|
|
82
|
-
parameters = tool.parameters;
|
|
83
|
-
} catch {
|
|
84
|
-
diagnostics.push({
|
|
85
|
-
toolIndex,
|
|
86
|
-
toolName: name,
|
|
87
|
-
violations: [`${name}.parameters is unreadable`]
|
|
88
|
-
});
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
const schemaProjection = projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
|
|
92
|
-
if (!isRecord(schemaProjection.schema) || schemaProjection.violations.length > 0) {
|
|
93
|
-
diagnostics.push({
|
|
94
|
-
toolIndex,
|
|
95
|
-
toolName: name,
|
|
96
|
-
violations: schemaProjection.violations.length > 0 ? schemaProjection.violations : [`${name}.parameters must be a JSON object schema`]
|
|
97
|
-
});
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
let descriptionValue;
|
|
101
|
-
try {
|
|
102
|
-
descriptionValue = tool.description;
|
|
103
|
-
} catch {}
|
|
104
|
-
const description = typeof descriptionValue === "string" ? descriptionValue : void 0;
|
|
105
|
-
projectedTools.push({
|
|
106
|
-
toolIndex,
|
|
107
|
-
name,
|
|
108
|
-
...description !== void 0 ? { description } : {},
|
|
109
|
-
parameters: schemaProjection.schema
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
inputToolCount,
|
|
114
|
-
tools: projectedTools,
|
|
115
|
-
diagnostics
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function requireProjectedFunction(name, projection, choiceLabel) {
|
|
119
|
-
if (!projection.tools.some((tool) => tool.name === name)) throw new Error(`${choiceLabel} requested unavailable tool "${name}" after schema conversion`);
|
|
120
|
-
}
|
|
121
|
-
/** Keeps Responses tool choices aligned with surviving function schemas. */
|
|
122
|
-
function reconcileOpenAIResponsesToolChoice(choice, projection) {
|
|
123
|
-
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
124
|
-
if (choice === "required") {
|
|
125
|
-
if (projection.tools.length === 0) throw new Error("OpenAI Responses tool_choice requires a tool, but no tools survived schema conversion");
|
|
126
|
-
return choice;
|
|
127
|
-
}
|
|
128
|
-
if (choice === "none" || !isRecord(choice)) return choice;
|
|
129
|
-
const choiceType = choice.type;
|
|
130
|
-
if (choiceType === "function") {
|
|
131
|
-
const functionName = choice.name;
|
|
132
|
-
if (typeof functionName !== "string") return choice;
|
|
133
|
-
requireProjectedFunction(functionName, projection, "OpenAI Responses tool_choice");
|
|
134
|
-
return {
|
|
135
|
-
type: "function",
|
|
136
|
-
name: functionName
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
if (choiceType !== "allowed_tools") return choice;
|
|
140
|
-
const mode = choice.mode;
|
|
141
|
-
const tools = choice.tools;
|
|
142
|
-
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
143
|
-
const normalizedAllowedTools = [];
|
|
144
|
-
for (const tool of tools) {
|
|
145
|
-
if (!isRecord(tool) || tool.type !== "function") {
|
|
146
|
-
normalizedAllowedTools.push(tool);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
const functionName = tool.name;
|
|
150
|
-
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
151
|
-
type: "function",
|
|
152
|
-
name: functionName
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
if (normalizedAllowedTools.length === 0) {
|
|
156
|
-
if (mode === "auto") return "none";
|
|
157
|
-
throw new Error("OpenAI Responses tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
type: "allowed_tools",
|
|
161
|
-
mode,
|
|
162
|
-
tools: normalizedAllowedTools
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
/** Keeps Chat Completions tool choices aligned with surviving function schemas. */
|
|
166
|
-
function reconcileOpenAICompletionsToolChoice(choice, projection) {
|
|
167
|
-
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
168
|
-
if (choice === "required") {
|
|
169
|
-
if (projection.tools.length === 0) throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no tools survived schema conversion");
|
|
170
|
-
return choice;
|
|
171
|
-
}
|
|
172
|
-
if (choice === "none" || !isRecord(choice)) return choice;
|
|
173
|
-
const choiceType = choice.type;
|
|
174
|
-
if (choiceType === "custom") throw new Error("OpenAI Chat Completions custom tool_choice is unsupported because this adapter emits function tools only");
|
|
175
|
-
if (choiceType === "function") {
|
|
176
|
-
const functionChoice = choice.function;
|
|
177
|
-
if (!isRecord(functionChoice)) return choice;
|
|
178
|
-
const functionName = functionChoice.name;
|
|
179
|
-
if (typeof functionName !== "string") return choice;
|
|
180
|
-
requireProjectedFunction(functionName, projection, "OpenAI Chat Completions tool_choice");
|
|
181
|
-
return {
|
|
182
|
-
type: "function",
|
|
183
|
-
function: { name: functionName }
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
if (choiceType !== "allowed_tools") return choice;
|
|
187
|
-
const allowedConfig = choice.allowed_tools;
|
|
188
|
-
if (!isRecord(allowedConfig)) return choice;
|
|
189
|
-
const mode = allowedConfig.mode;
|
|
190
|
-
const tools = allowedConfig.tools;
|
|
191
|
-
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
192
|
-
const normalizedAllowedTools = [];
|
|
193
|
-
for (const tool of tools) {
|
|
194
|
-
if (!isRecord(tool) || tool.type !== "function") continue;
|
|
195
|
-
const functionChoice = tool.function;
|
|
196
|
-
const functionName = isRecord(functionChoice) ? functionChoice.name : void 0;
|
|
197
|
-
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
198
|
-
type: "function",
|
|
199
|
-
function: { name: functionName }
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
if (normalizedAllowedTools.length === 0) {
|
|
203
|
-
if (mode === "auto") return "none";
|
|
204
|
-
throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
type: "allowed_tools",
|
|
208
|
-
allowed_tools: {
|
|
209
|
-
mode,
|
|
210
|
-
tools: normalizedAllowedTools
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
//#endregion
|
|
215
|
-
export { resolveModelRequestTimeoutMs as a, resolveProviderRequestCapabilities as c, buildGuardedModelFetch as i, resolveProviderRequestPolicyConfig as l, reconcileOpenAICompletionsToolChoice as n, resolveOpenAIStrictToolSetting as o, reconcileOpenAIResponsesToolChoice as r, resolveProviderEndpoint as s, projectOpenAITools as t, transformTransportMessages as u };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { o as truncateUtf16Safe } from "./tool-result-text-CTpIRbYd.mjs";
|
|
2
|
-
//#region packages/ai/src/utils/provider-error.ts
|
|
3
|
-
const MAX_ERROR_BODY_LENGTH = 4e3;
|
|
4
|
-
function stringify(value) {
|
|
5
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
6
|
-
try {
|
|
7
|
-
return JSON.stringify(value, (_key, candidate) => {
|
|
8
|
-
if (typeof candidate !== "object" || candidate === null) return candidate;
|
|
9
|
-
if (seen.has(candidate)) return "[Circular]";
|
|
10
|
-
seen.add(candidate);
|
|
11
|
-
return candidate;
|
|
12
|
-
}) ?? String(value);
|
|
13
|
-
} catch {
|
|
14
|
-
return String(value);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function readStatus(error) {
|
|
18
|
-
for (const value of [
|
|
19
|
-
error.status,
|
|
20
|
-
error.statusCode,
|
|
21
|
-
error.response?.status,
|
|
22
|
-
error.response?.statusCode
|
|
23
|
-
]) if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
24
|
-
}
|
|
25
|
-
function readBody(error) {
|
|
26
|
-
for (const value of [
|
|
27
|
-
error.body,
|
|
28
|
-
error.error,
|
|
29
|
-
error.response?.body,
|
|
30
|
-
error.response?.data
|
|
31
|
-
]) {
|
|
32
|
-
if (value === void 0 || value === null) continue;
|
|
33
|
-
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) continue;
|
|
34
|
-
const body = (typeof value === "string" ? value : stringify(value)).trim();
|
|
35
|
-
if (body.length > 0) return body.length <= MAX_ERROR_BODY_LENGTH ? body : `${truncateUtf16Safe(body, MAX_ERROR_BODY_LENGTH)}... [truncated]`;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function formatProviderError(error) {
|
|
39
|
-
if (!(error instanceof Error)) return stringify(error);
|
|
40
|
-
const httpError = error;
|
|
41
|
-
const status = readStatus(httpError);
|
|
42
|
-
const body = readBody(httpError);
|
|
43
|
-
if (status === void 0 || body === void 0 || error.message.includes(body)) return error.message;
|
|
44
|
-
return `${status}: ${body}`;
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
export { formatProviderError as t };
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
//#region packages/ai/src/utils/sanitize-unicode.ts
|
|
2
|
-
/**
|
|
3
|
-
* Removes unpaired Unicode surrogate characters from a string.
|
|
4
|
-
*
|
|
5
|
-
* Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
|
|
6
|
-
* or vice versa) cause JSON serialization errors in many API providers.
|
|
7
|
-
*
|
|
8
|
-
* Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
|
|
9
|
-
* surrogates and will NOT be affected by this function.
|
|
10
|
-
*
|
|
11
|
-
* @param text - The text to sanitize
|
|
12
|
-
* @returns The sanitized text with unpaired surrogates removed
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* // Valid emoji (properly paired surrogates) are preserved
|
|
16
|
-
* sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
|
|
17
|
-
*
|
|
18
|
-
* // Unpaired high surrogate is removed
|
|
19
|
-
* const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
|
|
20
|
-
* sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
|
|
21
|
-
*/
|
|
22
|
-
function sanitizeSurrogates(text) {
|
|
23
|
-
return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
export { sanitizeSurrogates as t };
|