claudish 9.4.0 → 9.5.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 +1150 -577
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -715,7 +715,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
715
715
|
});
|
|
716
716
|
|
|
717
717
|
// src/version.ts
|
|
718
|
-
var VERSION = "9.
|
|
718
|
+
var VERSION = "9.5.0";
|
|
719
719
|
|
|
720
720
|
// src/logger.ts
|
|
721
721
|
import { appendFile, existsSync as existsSync2, mkdirSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -19045,6 +19045,28 @@ var init_remote_provider_types = __esm(() => {
|
|
|
19045
19045
|
};
|
|
19046
19046
|
});
|
|
19047
19047
|
|
|
19048
|
+
// src/adapters/optional-param-rejection.ts
|
|
19049
|
+
function escapeName(name) {
|
|
19050
|
+
return name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19051
|
+
}
|
|
19052
|
+
function namesParameterField(errorText, param) {
|
|
19053
|
+
const p = escapeName(param);
|
|
19054
|
+
const tail = "(?![A-Za-z0-9_])";
|
|
19055
|
+
const quoted = new RegExp(`['"\`]${p}['"\`]`);
|
|
19056
|
+
const introduced = new RegExp("(?:parameter|argument|field|property|key|input)s?\\b" + "(?:[^A-Za-z0-9_]|\\b(?:supplied|provided|given|named|name|is|was|of|in|the|for|body|request|json)\\b){0,6}" + `${p}${tail}`, "i");
|
|
19057
|
+
const leading = new RegExp(`(?:^|["'])\\s*${p}\\s*:`);
|
|
19058
|
+
return quoted.test(errorText) || introduced.test(errorText) || leading.test(errorText);
|
|
19059
|
+
}
|
|
19060
|
+
function rejectedOptionalParams(errorText, candidates) {
|
|
19061
|
+
if (!errorText || !PARAMETER_COMPLAINT.test(errorText))
|
|
19062
|
+
return [];
|
|
19063
|
+
return candidates.filter((param) => namesParameterField(errorText, param));
|
|
19064
|
+
}
|
|
19065
|
+
var PARAMETER_COMPLAINT;
|
|
19066
|
+
var init_optional_param_rejection = __esm(() => {
|
|
19067
|
+
PARAMETER_COMPLAINT = /(unknown|unrecognized|unexpected|unsupported|not supported|does not support|invalid|not permitted|not allowed|extra (fields|inputs))/i;
|
|
19068
|
+
});
|
|
19069
|
+
|
|
19048
19070
|
// src/adapters/tool-name-utils.ts
|
|
19049
19071
|
function hashToolName(name) {
|
|
19050
19072
|
let h1 = 3735928559;
|
|
@@ -19061,20 +19083,46 @@ function hashToolName(name) {
|
|
|
19061
19083
|
const combined = 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
19062
19084
|
return combined.toString(16).padStart(8, "0").slice(0, 8);
|
|
19063
19085
|
}
|
|
19064
|
-
function
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
const
|
|
19069
|
-
const
|
|
19070
|
-
|
|
19071
|
-
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19086
|
+
function newToolNameBindings() {
|
|
19087
|
+
return { byEncoded: new Map, byOriginal: new Map };
|
|
19088
|
+
}
|
|
19089
|
+
function hashedForm(transformed, original, limit, salt) {
|
|
19090
|
+
const seed = salt === 0 ? original : `${original}#${salt}`;
|
|
19091
|
+
const prefix = transformed.slice(0, Math.max(0, limit - 9));
|
|
19092
|
+
return `${prefix}_${hashToolName(seed)}`;
|
|
19093
|
+
}
|
|
19094
|
+
function encodeToolName(original, limit, bindings) {
|
|
19095
|
+
const already = bindings.byOriginal.get(original);
|
|
19096
|
+
if (already !== undefined)
|
|
19097
|
+
return already;
|
|
19098
|
+
const transformed = original.replace(UNWIRABLE_CHARACTER, "_");
|
|
19099
|
+
const takenByAnother = (name) => {
|
|
19100
|
+
const owner = bindings.byEncoded.get(name);
|
|
19101
|
+
return owner !== undefined && owner !== original;
|
|
19102
|
+
};
|
|
19103
|
+
let encoded = transformed.length <= limit ? transformed : hashedForm(transformed, original, limit, 0);
|
|
19104
|
+
if (takenByAnother(encoded)) {
|
|
19105
|
+
let salt = 0;
|
|
19106
|
+
do {
|
|
19107
|
+
encoded = hashedForm(transformed, original, limit, salt++);
|
|
19108
|
+
} while (takenByAnother(encoded));
|
|
19109
|
+
}
|
|
19110
|
+
bindings.byEncoded.set(encoded, original);
|
|
19111
|
+
bindings.byOriginal.set(original, encoded);
|
|
19112
|
+
if (encoded !== original) {
|
|
19113
|
+
log(`[ToolName] Encoded: "${original}" -> "${encoded}" (${original.length} -> ${encoded.length})`);
|
|
19114
|
+
}
|
|
19115
|
+
return encoded;
|
|
19116
|
+
}
|
|
19117
|
+
function wireDecodesToolNames(format) {
|
|
19118
|
+
return format !== undefined && TOOL_NAME_DECODING_WIRES.includes(format);
|
|
19119
|
+
}
|
|
19120
|
+
var TOOL_NAME_SOURCE = "[A-Za-z_][A-Za-z0-9_.-]{0,63}", TOOL_NAME_SHAPE, UNWIRABLE_CHARACTER, TOOL_NAME_DECODING_WIRES;
|
|
19075
19121
|
var init_tool_name_utils = __esm(() => {
|
|
19076
19122
|
init_logger();
|
|
19077
19123
|
TOOL_NAME_SHAPE = new RegExp(`^${TOOL_NAME_SOURCE}$`);
|
|
19124
|
+
UNWIRABLE_CHARACTER = /[^A-Za-z0-9_-]/g;
|
|
19125
|
+
TOOL_NAME_DECODING_WIRES = ["openai-sse", "openai-responses-sse"];
|
|
19078
19126
|
});
|
|
19079
19127
|
|
|
19080
19128
|
// src/handlers/shared/format/openai-messages.ts
|
|
@@ -19106,13 +19154,154 @@ ${msg}`;
|
|
|
19106
19154
|
processAssistantMessage(msg, messages, simpleFormat);
|
|
19107
19155
|
}
|
|
19108
19156
|
}
|
|
19109
|
-
return messages;
|
|
19157
|
+
return normalizeMessageSequence(messages);
|
|
19110
19158
|
}
|
|
19111
|
-
function
|
|
19112
|
-
|
|
19113
|
-
|
|
19114
|
-
|
|
19159
|
+
function mergeUserContent(a, b) {
|
|
19160
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
19161
|
+
if (!a)
|
|
19162
|
+
return b;
|
|
19163
|
+
if (!b)
|
|
19164
|
+
return a;
|
|
19165
|
+
return `${a}
|
|
19166
|
+
|
|
19167
|
+
${b}`;
|
|
19168
|
+
}
|
|
19169
|
+
const toParts = (c) => {
|
|
19170
|
+
if (typeof c === "string")
|
|
19171
|
+
return c ? [{ type: "text", text: c }] : [];
|
|
19172
|
+
if (Array.isArray(c))
|
|
19173
|
+
return c;
|
|
19174
|
+
return;
|
|
19115
19175
|
};
|
|
19176
|
+
const pa = toParts(a);
|
|
19177
|
+
const pb = toParts(b);
|
|
19178
|
+
if (!pa || !pb)
|
|
19179
|
+
return;
|
|
19180
|
+
return [...pa, ...pb];
|
|
19181
|
+
}
|
|
19182
|
+
function pushUserMessage(out, msg) {
|
|
19183
|
+
const prev = out[out.length - 1];
|
|
19184
|
+
if (prev?.role === "user") {
|
|
19185
|
+
const merged = mergeUserContent(prev.content, msg.content);
|
|
19186
|
+
if (merged !== undefined) {
|
|
19187
|
+
prev.content = merged;
|
|
19188
|
+
return;
|
|
19189
|
+
}
|
|
19190
|
+
}
|
|
19191
|
+
out.push(msg);
|
|
19192
|
+
}
|
|
19193
|
+
function normalizeMessageSequence(messages) {
|
|
19194
|
+
const out = [];
|
|
19195
|
+
let openRound = null;
|
|
19196
|
+
let collected = [];
|
|
19197
|
+
const flushRound = (isFinal = false) => {
|
|
19198
|
+
if (!openRound)
|
|
19199
|
+
return;
|
|
19200
|
+
if (isFinal && collected.length === 0) {
|
|
19201
|
+
openRound = null;
|
|
19202
|
+
return;
|
|
19203
|
+
}
|
|
19204
|
+
out.push(...alignToolRound(openRound, collected));
|
|
19205
|
+
openRound = null;
|
|
19206
|
+
collected = [];
|
|
19207
|
+
};
|
|
19208
|
+
for (const msg of messages) {
|
|
19209
|
+
if (msg.role === "tool") {
|
|
19210
|
+
if (openRound) {
|
|
19211
|
+
collected.push(msg);
|
|
19212
|
+
continue;
|
|
19213
|
+
}
|
|
19214
|
+
log(`[OpenAIMessages] error \u2014 tool result ${msg.tool_call_id} answers no open tool round; ` + "re-emitted as a user message");
|
|
19215
|
+
const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
19216
|
+
pushUserMessage(out, { role: "user", content: `[Tool Result]: ${text}` });
|
|
19217
|
+
continue;
|
|
19218
|
+
}
|
|
19219
|
+
flushRound();
|
|
19220
|
+
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
19221
|
+
out.push(msg);
|
|
19222
|
+
openRound = msg;
|
|
19223
|
+
continue;
|
|
19224
|
+
}
|
|
19225
|
+
if (msg.role === "user")
|
|
19226
|
+
pushUserMessage(out, msg);
|
|
19227
|
+
else
|
|
19228
|
+
out.push(msg);
|
|
19229
|
+
}
|
|
19230
|
+
flushRound(true);
|
|
19231
|
+
return out;
|
|
19232
|
+
}
|
|
19233
|
+
function missingResultText(name) {
|
|
19234
|
+
const call = name ? `\`${name}\` call` : "call";
|
|
19235
|
+
return `[No tool result was provided for this ${call} \u2014 it was interrupted, cancelled, ` + "or dropped from the conversation history.]";
|
|
19236
|
+
}
|
|
19237
|
+
function alignToolRound(assistant, collected) {
|
|
19238
|
+
const calls = Array.isArray(assistant.tool_calls) ? assistant.tool_calls : [];
|
|
19239
|
+
const byId = new Map;
|
|
19240
|
+
for (const m of collected) {
|
|
19241
|
+
const list = byId.get(m.tool_call_id);
|
|
19242
|
+
if (list)
|
|
19243
|
+
list.push(m);
|
|
19244
|
+
else
|
|
19245
|
+
byId.set(m.tool_call_id, [m]);
|
|
19246
|
+
}
|
|
19247
|
+
const ordered = [];
|
|
19248
|
+
let synthesized = 0;
|
|
19249
|
+
for (const call of calls) {
|
|
19250
|
+
const matched = byId.get(call.id);
|
|
19251
|
+
if (matched) {
|
|
19252
|
+
ordered.push(...matched);
|
|
19253
|
+
byId.delete(call.id);
|
|
19254
|
+
continue;
|
|
19255
|
+
}
|
|
19256
|
+
synthesized++;
|
|
19257
|
+
log(`[OpenAIMessages] error \u2014 tool call ${call.id} (${call.function?.name || "?"}) has no ` + "result; a synthetic tool message names the omission");
|
|
19258
|
+
ordered.push({
|
|
19259
|
+
role: "tool",
|
|
19260
|
+
content: missingResultText(call.function?.name || ""),
|
|
19261
|
+
tool_call_id: call.id
|
|
19262
|
+
});
|
|
19263
|
+
}
|
|
19264
|
+
let dropped = 0;
|
|
19265
|
+
for (const [id, list] of byId) {
|
|
19266
|
+
dropped += list.length;
|
|
19267
|
+
log(`[OpenAIMessages] error \u2014 tool result ${id} matches no call in the round it follows; dropped`);
|
|
19268
|
+
}
|
|
19269
|
+
const reordered = ordered.some((m, i) => m !== collected[i]);
|
|
19270
|
+
if (reordered && !synthesized && !dropped) {
|
|
19271
|
+
log(`[OpenAIMessages] Reordered ${ordered.length} tool results to their tool_calls order`);
|
|
19272
|
+
}
|
|
19273
|
+
return ordered;
|
|
19274
|
+
}
|
|
19275
|
+
function imageBlockToUrlPart(block) {
|
|
19276
|
+
const source = block?.source;
|
|
19277
|
+
if (!source || typeof source !== "object") {
|
|
19278
|
+
log("[OpenAIMessages] Dropping image block: error \u2014 no source object");
|
|
19279
|
+
return null;
|
|
19280
|
+
}
|
|
19281
|
+
const url = typeof source.url === "string" ? source.url : "";
|
|
19282
|
+
const data = typeof source.data === "string" ? source.data : "";
|
|
19283
|
+
const kind = source.type || (url ? "url" : data ? "base64" : "");
|
|
19284
|
+
if (kind === "url") {
|
|
19285
|
+
if (!url) {
|
|
19286
|
+
log("[OpenAIMessages] Dropping image block: error \u2014 url source carries no url");
|
|
19287
|
+
return null;
|
|
19288
|
+
}
|
|
19289
|
+
return { type: "image_url", image_url: { url } };
|
|
19290
|
+
}
|
|
19291
|
+
if (kind === "base64") {
|
|
19292
|
+
if (!data) {
|
|
19293
|
+
log("[OpenAIMessages] Dropping image block: error \u2014 base64 source carries no data");
|
|
19294
|
+
return null;
|
|
19295
|
+
}
|
|
19296
|
+
const mediaType = typeof source.media_type === "string" ? source.media_type : "";
|
|
19297
|
+
if (!mediaType) {
|
|
19298
|
+
log("[OpenAIMessages] Dropping image block: error \u2014 base64 source carries no media_type");
|
|
19299
|
+
return null;
|
|
19300
|
+
}
|
|
19301
|
+
return { type: "image_url", image_url: { url: `data:${mediaType};base64,${data}` } };
|
|
19302
|
+
}
|
|
19303
|
+
log(`[OpenAIMessages] Dropping image block: error \u2014 unsupported source type ${kind || "(none)"}`);
|
|
19304
|
+
return null;
|
|
19116
19305
|
}
|
|
19117
19306
|
function processUserMessage(msg, messages, simpleFormat = false) {
|
|
19118
19307
|
if (Array.isArray(msg.content)) {
|
|
@@ -19129,7 +19318,9 @@ function processUserMessage(msg, messages, simpleFormat = false) {
|
|
|
19129
19318
|
}
|
|
19130
19319
|
} else if (block.type === "image") {
|
|
19131
19320
|
if (!simpleFormat) {
|
|
19132
|
-
|
|
19321
|
+
const part = imageBlockToUrlPart(block);
|
|
19322
|
+
if (part)
|
|
19323
|
+
contentParts.push(part);
|
|
19133
19324
|
}
|
|
19134
19325
|
} else if (block.type === "tool_result") {
|
|
19135
19326
|
if (seen.has(block.tool_use_id))
|
|
@@ -19141,12 +19332,21 @@ function processUserMessage(msg, messages, simpleFormat = false) {
|
|
|
19141
19332
|
} else if (Array.isArray(block.content)) {
|
|
19142
19333
|
const texts = [];
|
|
19143
19334
|
const others = [];
|
|
19335
|
+
let forwardedImages = 0;
|
|
19336
|
+
let droppedImages = 0;
|
|
19144
19337
|
for (const inner of block.content) {
|
|
19145
19338
|
if (inner.type === "text") {
|
|
19146
19339
|
texts.push(inner.text);
|
|
19147
19340
|
} else if (inner.type === "image" && inner.source) {
|
|
19148
|
-
if (!simpleFormat)
|
|
19149
|
-
|
|
19341
|
+
if (!simpleFormat) {
|
|
19342
|
+
const part = imageBlockToUrlPart(inner);
|
|
19343
|
+
if (part) {
|
|
19344
|
+
toolResultImages.push(part);
|
|
19345
|
+
forwardedImages++;
|
|
19346
|
+
} else {
|
|
19347
|
+
droppedImages++;
|
|
19348
|
+
}
|
|
19349
|
+
}
|
|
19150
19350
|
} else {
|
|
19151
19351
|
others.push(inner);
|
|
19152
19352
|
}
|
|
@@ -19157,7 +19357,12 @@ function processUserMessage(msg, messages, simpleFormat = false) {
|
|
|
19157
19357
|
resultText += (resultText ? `
|
|
19158
19358
|
` : "") + JSON.stringify(others);
|
|
19159
19359
|
if (!resultText) {
|
|
19160
|
-
|
|
19360
|
+
if (forwardedImages)
|
|
19361
|
+
resultText = "[image returned; see following message]";
|
|
19362
|
+
else if (droppedImages)
|
|
19363
|
+
resultText = "[image returned, but its source could not be forwarded]";
|
|
19364
|
+
else
|
|
19365
|
+
resultText = "";
|
|
19161
19366
|
}
|
|
19162
19367
|
} else {
|
|
19163
19368
|
resultText = JSON.stringify(block.content);
|
|
@@ -19243,6 +19448,9 @@ function processAssistantMessage(msg, messages, simpleFormat = false) {
|
|
|
19243
19448
|
messages.push({ role: "assistant", content: msg.content });
|
|
19244
19449
|
}
|
|
19245
19450
|
}
|
|
19451
|
+
var init_openai_messages = __esm(() => {
|
|
19452
|
+
init_logger();
|
|
19453
|
+
});
|
|
19246
19454
|
|
|
19247
19455
|
// src/transform.ts
|
|
19248
19456
|
function removeUriFormat(schema) {
|
|
@@ -19452,6 +19660,45 @@ function summarizeToolParameters(schema) {
|
|
|
19452
19660
|
}
|
|
19453
19661
|
return summarized;
|
|
19454
19662
|
}
|
|
19663
|
+
function mapToolChoiceToOpenAI(choice, encodeName) {
|
|
19664
|
+
if (!choice)
|
|
19665
|
+
return;
|
|
19666
|
+
const { type, name } = choice;
|
|
19667
|
+
if (type === "tool" && name) {
|
|
19668
|
+
return { type: "function", function: { name: encodeName ? encodeName(name) : name } };
|
|
19669
|
+
}
|
|
19670
|
+
if (type === "any")
|
|
19671
|
+
return "required";
|
|
19672
|
+
if (type === "auto" || type === "none")
|
|
19673
|
+
return type;
|
|
19674
|
+
return;
|
|
19675
|
+
}
|
|
19676
|
+
function mapToolChoiceToResponsesAPI(choice, encodeName) {
|
|
19677
|
+
const mapped = mapToolChoiceToOpenAI(choice, encodeName);
|
|
19678
|
+
if (mapped === undefined || typeof mapped === "string")
|
|
19679
|
+
return mapped;
|
|
19680
|
+
return { type: "function", name: mapped.function.name };
|
|
19681
|
+
}
|
|
19682
|
+
function mapToolChoiceToGemini(choice, encodeName) {
|
|
19683
|
+
if (!choice)
|
|
19684
|
+
return;
|
|
19685
|
+
const { type, name } = choice;
|
|
19686
|
+
if (type === "tool" && name) {
|
|
19687
|
+
return {
|
|
19688
|
+
functionCallingConfig: {
|
|
19689
|
+
mode: "ANY",
|
|
19690
|
+
allowedFunctionNames: [encodeName ? encodeName(name) : name]
|
|
19691
|
+
}
|
|
19692
|
+
};
|
|
19693
|
+
}
|
|
19694
|
+
if (type === "any")
|
|
19695
|
+
return { functionCallingConfig: { mode: "ANY" } };
|
|
19696
|
+
if (type === "auto")
|
|
19697
|
+
return { functionCallingConfig: { mode: "AUTO" } };
|
|
19698
|
+
if (type === "none")
|
|
19699
|
+
return { functionCallingConfig: { mode: "NONE" } };
|
|
19700
|
+
return;
|
|
19701
|
+
}
|
|
19455
19702
|
var PORTABLE_ESCAPE_LETTERS, NAMED_SCHEMA_MAPS;
|
|
19456
19703
|
var init_openai_tools = __esm(() => {
|
|
19457
19704
|
init_logger();
|
|
@@ -19494,7 +19741,11 @@ function isEffortLevel(value) {
|
|
|
19494
19741
|
class BaseAPIFormat {
|
|
19495
19742
|
modelId;
|
|
19496
19743
|
wireFormat;
|
|
19497
|
-
|
|
19744
|
+
responseWireFormat;
|
|
19745
|
+
setResponseWireFormat(format) {
|
|
19746
|
+
this.responseWireFormat = format;
|
|
19747
|
+
}
|
|
19748
|
+
toolNameBindings = newToolNameBindings();
|
|
19498
19749
|
constructor(modelId, wireFormat) {
|
|
19499
19750
|
this.modelId = modelId;
|
|
19500
19751
|
this.wireFormat = wireFormat;
|
|
@@ -19505,20 +19756,52 @@ class BaseAPIFormat {
|
|
|
19505
19756
|
getWireFormat() {
|
|
19506
19757
|
return this.wireFormat;
|
|
19507
19758
|
}
|
|
19759
|
+
recoverFromRejection(payload, errorText) {
|
|
19760
|
+
return this.recoverFromSamplingParamRejection(payload, errorText);
|
|
19761
|
+
}
|
|
19762
|
+
recoverFromSamplingParamRejection(payload, errorText) {
|
|
19763
|
+
if (!payload)
|
|
19764
|
+
return null;
|
|
19765
|
+
const present = OPTIONAL_SAMPLING_PARAMS.filter((p) => payload[p] !== undefined);
|
|
19766
|
+
if (present.length === 0)
|
|
19767
|
+
return null;
|
|
19768
|
+
const rejected = rejectedOptionalParams(errorText, present);
|
|
19769
|
+
if (rejected.length === 0)
|
|
19770
|
+
return null;
|
|
19771
|
+
const next = { ...payload };
|
|
19772
|
+
for (const p of rejected)
|
|
19773
|
+
delete next[p];
|
|
19774
|
+
return { payload: next, note: `dropped ${rejected.join(", ")} for ${this.modelId}` };
|
|
19775
|
+
}
|
|
19776
|
+
applyOpenAISamplingParams(payload, claudeRequest) {
|
|
19777
|
+
if (!payload || !claudeRequest)
|
|
19778
|
+
return;
|
|
19779
|
+
const sequences = claudeRequest.stop_sequences;
|
|
19780
|
+
if (Array.isArray(sequences)) {
|
|
19781
|
+
const usable = sequences.filter((s) => typeof s === "string" && s.length > 0);
|
|
19782
|
+
if (usable.length > 0)
|
|
19783
|
+
payload.stop = usable;
|
|
19784
|
+
}
|
|
19785
|
+
if (claudeRequest.top_p !== undefined && claudeRequest.top_p !== null) {
|
|
19786
|
+
payload.top_p = claudeRequest.top_p;
|
|
19787
|
+
}
|
|
19788
|
+
}
|
|
19508
19789
|
getToolNameLimit() {
|
|
19509
|
-
|
|
19790
|
+
const wire = this.responseWireFormat ?? this.wireFormat ?? this.getStreamFormat();
|
|
19791
|
+
return wireDecodesToolNames(wire) ? OPENAI_TOOL_NAME_LIMIT : null;
|
|
19510
19792
|
}
|
|
19511
19793
|
getMaxToolCount() {
|
|
19512
19794
|
return null;
|
|
19513
19795
|
}
|
|
19514
19796
|
getToolNameMap() {
|
|
19515
|
-
return this.
|
|
19797
|
+
return this.toolNameBindings.byEncoded;
|
|
19516
19798
|
}
|
|
19517
19799
|
restoreToolName(name) {
|
|
19518
|
-
return this.
|
|
19800
|
+
return this.toolNameBindings.byEncoded.get(name) || name;
|
|
19519
19801
|
}
|
|
19520
19802
|
prepareRequest(request, originalRequest) {
|
|
19521
19803
|
const prepared = this.prepareRequestCommon(request, originalRequest) ?? request;
|
|
19804
|
+
this.encodeToolNames(prepared);
|
|
19522
19805
|
if (!this.isAnthropicWire()) {
|
|
19523
19806
|
return this.applyNativeReasoning(prepared, originalRequest) ?? prepared;
|
|
19524
19807
|
}
|
|
@@ -19656,7 +19939,7 @@ class BaseAPIFormat {
|
|
|
19656
19939
|
return;
|
|
19657
19940
|
}
|
|
19658
19941
|
reset() {
|
|
19659
|
-
this.
|
|
19942
|
+
this.toolNameBindings = newToolNameBindings();
|
|
19660
19943
|
}
|
|
19661
19944
|
convertMessages(claudeRequest, filterIdentityFn) {
|
|
19662
19945
|
return convertMessagesToOpenAI(claudeRequest, this.modelId, filterIdentityFn);
|
|
@@ -19672,6 +19955,10 @@ class BaseAPIFormat {
|
|
|
19672
19955
|
};
|
|
19673
19956
|
if (tools.length > 0) {
|
|
19674
19957
|
payload.tools = tools;
|
|
19958
|
+
const toolChoice = mapToolChoiceToOpenAI(claudeRequest.tool_choice);
|
|
19959
|
+
if (toolChoice !== undefined) {
|
|
19960
|
+
payload.tool_choice = toolChoice;
|
|
19961
|
+
}
|
|
19675
19962
|
}
|
|
19676
19963
|
if (claudeRequest.max_tokens) {
|
|
19677
19964
|
payload.max_tokens = claudeRequest.max_tokens;
|
|
@@ -19679,6 +19966,7 @@ class BaseAPIFormat {
|
|
|
19679
19966
|
if (claudeRequest.temperature !== undefined) {
|
|
19680
19967
|
payload.temperature = claudeRequest.temperature;
|
|
19681
19968
|
}
|
|
19969
|
+
this.applyOpenAISamplingParams(payload, claudeRequest);
|
|
19682
19970
|
return payload;
|
|
19683
19971
|
}
|
|
19684
19972
|
getStreamFormat() {
|
|
@@ -19696,50 +19984,56 @@ class BaseAPIFormat {
|
|
|
19696
19984
|
shouldFilterThinking() {
|
|
19697
19985
|
return this.isAnthropicWire();
|
|
19698
19986
|
}
|
|
19699
|
-
|
|
19987
|
+
encodeToolNames(request) {
|
|
19700
19988
|
const limit = this.getToolNameLimit();
|
|
19701
|
-
if (!limit || !request
|
|
19989
|
+
if (!limit || !request)
|
|
19702
19990
|
return;
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19708
|
-
if (tool
|
|
19709
|
-
tool.
|
|
19710
|
-
} else if (tool.name) {
|
|
19711
|
-
tool.name = truncated;
|
|
19991
|
+
const encode = (name) => encodeToolName(name, limit, this.toolNameBindings);
|
|
19992
|
+
if (Array.isArray(request.tools)) {
|
|
19993
|
+
for (const tool of request.tools) {
|
|
19994
|
+
if (tool?.function?.name) {
|
|
19995
|
+
tool.function.name = encode(tool.function.name);
|
|
19996
|
+
} else if (tool?.name) {
|
|
19997
|
+
tool.name = encode(tool.name);
|
|
19712
19998
|
}
|
|
19713
19999
|
}
|
|
19714
20000
|
}
|
|
19715
|
-
|
|
19716
|
-
|
|
19717
|
-
|
|
19718
|
-
|
|
19719
|
-
return;
|
|
19720
|
-
for (const msg of messages) {
|
|
19721
|
-
if (msg.role === "assistant" && Array.isArray(msg.tool_calls)) {
|
|
20001
|
+
if (Array.isArray(request.messages)) {
|
|
20002
|
+
for (const msg of request.messages) {
|
|
20003
|
+
if (msg?.role !== "assistant" || !Array.isArray(msg.tool_calls))
|
|
20004
|
+
continue;
|
|
19722
20005
|
for (const tc of msg.tool_calls) {
|
|
19723
|
-
|
|
19724
|
-
|
|
19725
|
-
const truncated = truncateToolName(name, limit);
|
|
19726
|
-
tc.function.name = truncated;
|
|
19727
|
-
if (!this.toolNameMap.has(truncated)) {
|
|
19728
|
-
this.toolNameMap.set(truncated, name);
|
|
19729
|
-
}
|
|
19730
|
-
}
|
|
20006
|
+
if (tc?.function?.name)
|
|
20007
|
+
tc.function.name = encode(tc.function.name);
|
|
19731
20008
|
}
|
|
19732
20009
|
}
|
|
19733
20010
|
}
|
|
20011
|
+
if (Array.isArray(request.input)) {
|
|
20012
|
+
for (const item of request.input) {
|
|
20013
|
+
if (item?.type === "function_call" && item.name)
|
|
20014
|
+
item.name = encode(item.name);
|
|
20015
|
+
}
|
|
20016
|
+
}
|
|
20017
|
+
const choice = request.tool_choice;
|
|
20018
|
+
if (choice && typeof choice === "object") {
|
|
20019
|
+
if (choice.function?.name) {
|
|
20020
|
+
choice.function.name = encode(choice.function.name);
|
|
20021
|
+
} else if (choice.name) {
|
|
20022
|
+
choice.name = encode(choice.name);
|
|
20023
|
+
}
|
|
20024
|
+
}
|
|
19734
20025
|
}
|
|
19735
20026
|
}
|
|
19736
|
-
var EFFORT_ORDER, EFFORT_LEVELS, NON_ANTHROPIC_REASONING_FIELDS, DefaultAPIFormat;
|
|
20027
|
+
var OPTIONAL_SAMPLING_PARAMS, OPENAI_TOOL_NAME_LIMIT = 64, EFFORT_ORDER, EFFORT_LEVELS, NON_ANTHROPIC_REASONING_FIELDS, DefaultAPIFormat;
|
|
19737
20028
|
var init_base_api_format = __esm(() => {
|
|
19738
20029
|
init_remote_provider_types();
|
|
19739
20030
|
init_logger();
|
|
19740
20031
|
init_model_catalog();
|
|
20032
|
+
init_optional_param_rejection();
|
|
19741
20033
|
init_tool_name_utils();
|
|
20034
|
+
init_openai_messages();
|
|
19742
20035
|
init_openai_tools();
|
|
20036
|
+
OPTIONAL_SAMPLING_PARAMS = ["stop", "top_p"];
|
|
19743
20037
|
EFFORT_ORDER = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
19744
20038
|
EFFORT_LEVELS = EFFORT_ORDER;
|
|
19745
20039
|
NON_ANTHROPIC_REASONING_FIELDS = [
|
|
@@ -19922,6 +20216,7 @@ function normalizeCodexModel(modelId) {
|
|
|
19922
20216
|
}
|
|
19923
20217
|
var CodexAPIFormat;
|
|
19924
20218
|
var init_codex_api_format = __esm(() => {
|
|
20219
|
+
init_openai_tools();
|
|
19925
20220
|
init_logger();
|
|
19926
20221
|
init_base_api_format();
|
|
19927
20222
|
init_reasoning_cache();
|
|
@@ -19987,6 +20282,10 @@ var init_codex_api_format = __esm(() => {
|
|
|
19987
20282
|
}
|
|
19988
20283
|
return tool;
|
|
19989
20284
|
});
|
|
20285
|
+
const toolChoice = mapToolChoiceToResponsesAPI(claudeRequest.tool_choice);
|
|
20286
|
+
if (toolChoice !== undefined) {
|
|
20287
|
+
payload.tool_choice = toolChoice;
|
|
20288
|
+
}
|
|
19990
20289
|
}
|
|
19991
20290
|
return payload;
|
|
19992
20291
|
}
|
|
@@ -20568,31 +20867,308 @@ function filterIdentity(content) {
|
|
|
20568
20867
|
`);
|
|
20569
20868
|
}
|
|
20570
20869
|
|
|
20870
|
+
// src/handlers/shared/schema-validate.ts
|
|
20871
|
+
function missingRequired(schema, args) {
|
|
20872
|
+
const required = schema?.required;
|
|
20873
|
+
if (!Array.isArray(required) || required.length === 0)
|
|
20874
|
+
return [];
|
|
20875
|
+
const supplied = args ?? {};
|
|
20876
|
+
return required.filter((key) => {
|
|
20877
|
+
if (typeof key !== "string")
|
|
20878
|
+
return false;
|
|
20879
|
+
if (!Object.hasOwn(supplied, key))
|
|
20880
|
+
return true;
|
|
20881
|
+
const value = supplied[key];
|
|
20882
|
+
return value === undefined || value === null;
|
|
20883
|
+
});
|
|
20884
|
+
}
|
|
20885
|
+
function isAbsent(args, key) {
|
|
20886
|
+
if (!Object.hasOwn(args, key))
|
|
20887
|
+
return true;
|
|
20888
|
+
const value = args[key];
|
|
20889
|
+
return value === undefined || value === null;
|
|
20890
|
+
}
|
|
20891
|
+
function declaredTypes(node) {
|
|
20892
|
+
if (!node)
|
|
20893
|
+
return [];
|
|
20894
|
+
const t = node.type;
|
|
20895
|
+
if (typeof t === "string")
|
|
20896
|
+
return [t];
|
|
20897
|
+
if (Array.isArray(t))
|
|
20898
|
+
return t.filter((x) => typeof x === "string");
|
|
20899
|
+
if (Array.isArray(node.enum) && node.enum.length > 0) {
|
|
20900
|
+
const kinds = new Set;
|
|
20901
|
+
for (const member of node.enum) {
|
|
20902
|
+
if (member === null || member === undefined)
|
|
20903
|
+
continue;
|
|
20904
|
+
if (Array.isArray(member))
|
|
20905
|
+
kinds.add("array");
|
|
20906
|
+
else if (typeof member === "object")
|
|
20907
|
+
kinds.add("object");
|
|
20908
|
+
else if (typeof member === "number")
|
|
20909
|
+
kinds.add(Number.isInteger(member) ? "integer" : "number");
|
|
20910
|
+
else if (typeof member === "boolean")
|
|
20911
|
+
kinds.add("boolean");
|
|
20912
|
+
else if (typeof member === "string")
|
|
20913
|
+
kinds.add("string");
|
|
20914
|
+
}
|
|
20915
|
+
return [...kinds];
|
|
20916
|
+
}
|
|
20917
|
+
return [];
|
|
20918
|
+
}
|
|
20919
|
+
function coerceOne(value, type, node) {
|
|
20920
|
+
switch (type) {
|
|
20921
|
+
case "string":
|
|
20922
|
+
return typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" ? String(value) : undefined;
|
|
20923
|
+
case "number":
|
|
20924
|
+
case "integer": {
|
|
20925
|
+
if (typeof value === "number") {
|
|
20926
|
+
return type === "integer" && !Number.isInteger(value) ? undefined : value;
|
|
20927
|
+
}
|
|
20928
|
+
if (typeof value !== "string" || !FULL_NUMBER.test(value.trim()))
|
|
20929
|
+
return;
|
|
20930
|
+
const n = Number(value.trim());
|
|
20931
|
+
if (!Number.isFinite(n))
|
|
20932
|
+
return;
|
|
20933
|
+
return type === "integer" && !Number.isInteger(n) ? undefined : n;
|
|
20934
|
+
}
|
|
20935
|
+
case "boolean": {
|
|
20936
|
+
if (typeof value === "boolean")
|
|
20937
|
+
return value;
|
|
20938
|
+
if (typeof value !== "string")
|
|
20939
|
+
return;
|
|
20940
|
+
const s = value.trim().toLowerCase();
|
|
20941
|
+
return s === "true" ? true : s === "false" ? false : undefined;
|
|
20942
|
+
}
|
|
20943
|
+
case "array": {
|
|
20944
|
+
const arr = Array.isArray(value) ? value : parseJsonOfKind(value, "array");
|
|
20945
|
+
if (!Array.isArray(arr))
|
|
20946
|
+
return;
|
|
20947
|
+
const items = node?.items;
|
|
20948
|
+
if (!items)
|
|
20949
|
+
return arr;
|
|
20950
|
+
return arr.map((el) => {
|
|
20951
|
+
const target = declaredTypes(items);
|
|
20952
|
+
for (const t of target) {
|
|
20953
|
+
const c = coerceOne(el, t, items);
|
|
20954
|
+
if (c !== undefined)
|
|
20955
|
+
return c;
|
|
20956
|
+
}
|
|
20957
|
+
return el;
|
|
20958
|
+
});
|
|
20959
|
+
}
|
|
20960
|
+
case "object":
|
|
20961
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : parseJsonOfKind(value, "object");
|
|
20962
|
+
default:
|
|
20963
|
+
return;
|
|
20964
|
+
}
|
|
20965
|
+
}
|
|
20966
|
+
function parseJsonOfKind(value, kind) {
|
|
20967
|
+
if (typeof value !== "string")
|
|
20968
|
+
return;
|
|
20969
|
+
try {
|
|
20970
|
+
const parsed = JSON.parse(value);
|
|
20971
|
+
if (kind === "array")
|
|
20972
|
+
return Array.isArray(parsed) ? parsed : undefined;
|
|
20973
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
|
|
20974
|
+
} catch {
|
|
20975
|
+
return;
|
|
20976
|
+
}
|
|
20977
|
+
}
|
|
20978
|
+
function coerceToSchema(schema, args) {
|
|
20979
|
+
const properties = schema?.properties;
|
|
20980
|
+
if (!properties)
|
|
20981
|
+
return { args, coerced: [] };
|
|
20982
|
+
const out = { ...args };
|
|
20983
|
+
const coerced = [];
|
|
20984
|
+
for (const [key, value] of Object.entries(args)) {
|
|
20985
|
+
const node = properties[key];
|
|
20986
|
+
if (!node || value === undefined || value === null)
|
|
20987
|
+
continue;
|
|
20988
|
+
const types = declaredTypes(node);
|
|
20989
|
+
if (types.length === 0)
|
|
20990
|
+
continue;
|
|
20991
|
+
if (types.some((t) => matchesType(value, t)))
|
|
20992
|
+
continue;
|
|
20993
|
+
for (const t of types) {
|
|
20994
|
+
const c = coerceOne(value, t, node);
|
|
20995
|
+
if (c !== undefined) {
|
|
20996
|
+
out[key] = c;
|
|
20997
|
+
coerced.push(key);
|
|
20998
|
+
break;
|
|
20999
|
+
}
|
|
21000
|
+
}
|
|
21001
|
+
}
|
|
21002
|
+
return { args: coerced.length > 0 ? out : args, coerced };
|
|
21003
|
+
}
|
|
21004
|
+
function matchesType(value, type) {
|
|
21005
|
+
switch (type) {
|
|
21006
|
+
case "string":
|
|
21007
|
+
return typeof value === "string";
|
|
21008
|
+
case "number":
|
|
21009
|
+
return typeof value === "number";
|
|
21010
|
+
case "integer":
|
|
21011
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
21012
|
+
case "boolean":
|
|
21013
|
+
return typeof value === "boolean";
|
|
21014
|
+
case "array":
|
|
21015
|
+
return Array.isArray(value);
|
|
21016
|
+
case "object":
|
|
21017
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
21018
|
+
case "null":
|
|
21019
|
+
return value === null;
|
|
21020
|
+
default:
|
|
21021
|
+
return false;
|
|
21022
|
+
}
|
|
21023
|
+
}
|
|
21024
|
+
function applySchemaDefaults(schema, args) {
|
|
21025
|
+
const properties = schema?.properties;
|
|
21026
|
+
const required = schema?.required;
|
|
21027
|
+
if (!properties || !Array.isArray(required))
|
|
21028
|
+
return { args, applied: [] };
|
|
21029
|
+
const out = { ...args };
|
|
21030
|
+
const applied = [];
|
|
21031
|
+
for (const key of required) {
|
|
21032
|
+
if (typeof key !== "string" || !isAbsent(out, key))
|
|
21033
|
+
continue;
|
|
21034
|
+
const node = properties[key];
|
|
21035
|
+
if (!node || !Object.hasOwn(node, "default") || node.default === undefined)
|
|
21036
|
+
continue;
|
|
21037
|
+
out[key] = node.default;
|
|
21038
|
+
applied.push(key);
|
|
21039
|
+
}
|
|
21040
|
+
return { args: applied.length > 0 ? out : args, applied };
|
|
21041
|
+
}
|
|
21042
|
+
function renameToDeclaredKeys(schema, args) {
|
|
21043
|
+
const properties = schema?.properties;
|
|
21044
|
+
const required = schema?.required;
|
|
21045
|
+
if (!properties || !Array.isArray(required))
|
|
21046
|
+
return { args, renamed: [] };
|
|
21047
|
+
const out = { ...args };
|
|
21048
|
+
const renamed = [];
|
|
21049
|
+
for (const target of required) {
|
|
21050
|
+
if (typeof target !== "string")
|
|
21051
|
+
continue;
|
|
21052
|
+
if (!properties[target] || !isAbsent(out, target))
|
|
21053
|
+
continue;
|
|
21054
|
+
for (const source of KEY_SYNONYMS[target] ?? []) {
|
|
21055
|
+
if (properties[source])
|
|
21056
|
+
continue;
|
|
21057
|
+
if (isAbsent(out, source))
|
|
21058
|
+
continue;
|
|
21059
|
+
out[target] = out[source];
|
|
21060
|
+
delete out[source];
|
|
21061
|
+
renamed.push(`${source}\u2192${target}`);
|
|
21062
|
+
break;
|
|
21063
|
+
}
|
|
21064
|
+
}
|
|
21065
|
+
return { args: renamed.length > 0 ? out : args, renamed };
|
|
21066
|
+
}
|
|
21067
|
+
var FULL_NUMBER, KEY_SYNONYMS;
|
|
21068
|
+
var init_schema_validate = __esm(() => {
|
|
21069
|
+
FULL_NUMBER = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
|
|
21070
|
+
KEY_SYNONYMS = {
|
|
21071
|
+
command: ["cmd", "shell", "script"],
|
|
21072
|
+
file_path: ["path", "file", "filename"],
|
|
21073
|
+
content: ["text", "data", "body"],
|
|
21074
|
+
pattern: ["query", "search", "regex", "glob"],
|
|
21075
|
+
query: ["search", "keyword"],
|
|
21076
|
+
prompt: ["query", "task"]
|
|
21077
|
+
};
|
|
21078
|
+
});
|
|
21079
|
+
|
|
20571
21080
|
// src/handlers/shared/tool-call-recovery.ts
|
|
20572
21081
|
function hasExtractableFunctionTag(text) {
|
|
20573
21082
|
return FUNCTION_TAG_PRESENT.test(text);
|
|
20574
21083
|
}
|
|
20575
|
-
function keepOnlyRealTools(extracted, knownToolNames) {
|
|
21084
|
+
function keepOnlyRealTools(extracted, knownToolNames, decodeToolName) {
|
|
20576
21085
|
const kept = [];
|
|
20577
21086
|
for (const call of extracted) {
|
|
20578
21087
|
if (!TOOL_NAME_SHAPE.test(call.name)) {
|
|
20579
21088
|
log(`[ToolRecovery] Dropped extracted call: name is not an identifier: ${JSON.stringify(call.name.slice(0, 120))}`);
|
|
20580
21089
|
continue;
|
|
20581
21090
|
}
|
|
21091
|
+
const decoded = decodeToolName ? decodeToolName(call.name) : call.name;
|
|
21092
|
+
const named = decoded === call.name ? call : { ...call, name: decoded };
|
|
20582
21093
|
if (!knownToolNames || knownToolNames.length === 0) {
|
|
20583
|
-
kept.push(
|
|
21094
|
+
kept.push(named);
|
|
20584
21095
|
continue;
|
|
20585
21096
|
}
|
|
20586
|
-
const canonical = knownToolNames.find((t) => t.toLowerCase() ===
|
|
21097
|
+
const canonical = knownToolNames.find((t) => t.toLowerCase() === named.name.toLowerCase());
|
|
20587
21098
|
if (!canonical) {
|
|
20588
|
-
log(`[ToolRecovery] Dropped extracted call for unadvertised tool: ${
|
|
21099
|
+
log(`[ToolRecovery] Dropped extracted call for unadvertised tool: ${named.name}`);
|
|
20589
21100
|
continue;
|
|
20590
21101
|
}
|
|
20591
|
-
kept.push(canonical ===
|
|
21102
|
+
kept.push(canonical === named.name ? named : { ...named, name: canonical });
|
|
20592
21103
|
}
|
|
20593
21104
|
return kept;
|
|
20594
21105
|
}
|
|
20595
|
-
function
|
|
21106
|
+
function parseFunctionTagEnvelope(text) {
|
|
21107
|
+
const body = text.trim();
|
|
21108
|
+
if (body.length === 0)
|
|
21109
|
+
return null;
|
|
21110
|
+
if (!body.startsWith("<function="))
|
|
21111
|
+
return null;
|
|
21112
|
+
const calls = [];
|
|
21113
|
+
let cursor = 0;
|
|
21114
|
+
while (cursor < body.length) {
|
|
21115
|
+
FUNCTION_TAG_AT_CURSOR.lastIndex = cursor;
|
|
21116
|
+
const open = FUNCTION_TAG_AT_CURSOR.exec(body);
|
|
21117
|
+
if (!open)
|
|
21118
|
+
return null;
|
|
21119
|
+
cursor = FUNCTION_TAG_AT_CURSOR.lastIndex;
|
|
21120
|
+
const args = {};
|
|
21121
|
+
while (cursor < body.length) {
|
|
21122
|
+
const rest = body.slice(cursor);
|
|
21123
|
+
const closeLen = /^\s*<\/function>/.exec(rest)?.[0].length;
|
|
21124
|
+
if (closeLen !== undefined) {
|
|
21125
|
+
cursor += closeLen;
|
|
21126
|
+
break;
|
|
21127
|
+
}
|
|
21128
|
+
if (/^\s*<function=/.test(rest))
|
|
21129
|
+
break;
|
|
21130
|
+
const lead = /^\s*/.exec(rest)?.[0].length ?? 0;
|
|
21131
|
+
PARAMETER_TAG_AT_CURSOR.lastIndex = cursor + lead;
|
|
21132
|
+
const param = PARAMETER_TAG_AT_CURSOR.exec(body);
|
|
21133
|
+
if (!param)
|
|
21134
|
+
return null;
|
|
21135
|
+
let valueStart = PARAMETER_TAG_AT_CURSOR.lastIndex;
|
|
21136
|
+
if (body[valueStart] === `
|
|
21137
|
+
`)
|
|
21138
|
+
valueStart += 1;
|
|
21139
|
+
const tail = body.slice(valueStart);
|
|
21140
|
+
const end = /<\/parameter>|<\/function>|<parameter=|<function=/.exec(tail);
|
|
21141
|
+
const raw = end ? tail.slice(0, end.index) : tail;
|
|
21142
|
+
args[param[1]] = raw.trim();
|
|
21143
|
+
cursor = valueStart + raw.length;
|
|
21144
|
+
const consumedClose = /^<\/parameter>/.exec(body.slice(cursor))?.[0].length;
|
|
21145
|
+
if (consumedClose !== undefined)
|
|
21146
|
+
cursor += consumedClose;
|
|
21147
|
+
}
|
|
21148
|
+
calls.push({ name: open[1], arguments: args, source: "xml_text" });
|
|
21149
|
+
const gap = /^\s*/.exec(body.slice(cursor))?.[0].length ?? 0;
|
|
21150
|
+
cursor += gap;
|
|
21151
|
+
}
|
|
21152
|
+
return calls.length > 0 ? calls : null;
|
|
21153
|
+
}
|
|
21154
|
+
function normalizeAgainstSchema(call, toolSchemas) {
|
|
21155
|
+
const schema = toolSchemas?.find((t) => t.name === call.name)?.input_schema;
|
|
21156
|
+
if (!schema)
|
|
21157
|
+
return call;
|
|
21158
|
+
const renamed = renameToDeclaredKeys(schema, call.arguments);
|
|
21159
|
+
const defaulted = applySchemaDefaults(schema, renamed.args);
|
|
21160
|
+
const coerced = coerceToSchema(schema, defaulted.args);
|
|
21161
|
+
if (renamed.renamed.length + defaulted.applied.length + coerced.coerced.length === 0) {
|
|
21162
|
+
return call;
|
|
21163
|
+
}
|
|
21164
|
+
log(`[ToolRecovery] Normalized ${call.name} against its schema: ` + `renamed=[${renamed.renamed}] defaults=[${defaulted.applied}] coerced=[${coerced.coerced}]`);
|
|
21165
|
+
return { ...call, arguments: coerced.args };
|
|
21166
|
+
}
|
|
21167
|
+
function extractToolCallsFromText(text, knownToolNames, toolSchemas, decodeToolName) {
|
|
21168
|
+
const envelope = parseFunctionTagEnvelope(text);
|
|
21169
|
+
if (envelope) {
|
|
21170
|
+
return keepOnlyRealTools(envelope, knownToolNames, decodeToolName).map((call) => normalizeAgainstSchema(call, toolSchemas));
|
|
21171
|
+
}
|
|
20596
21172
|
const extracted = [];
|
|
20597
21173
|
const qwenPattern = new RegExp(FUNCTION_TAG_SOURCE, "gi");
|
|
20598
21174
|
let match;
|
|
@@ -20719,73 +21295,6 @@ function extractToolCallsFromText(text, knownToolNames) {
|
|
|
20719
21295
|
while ((kvMatch = kvPattern.exec(paramText)) !== null) {
|
|
20720
21296
|
args[kvMatch[1]] = kvMatch[2];
|
|
20721
21297
|
}
|
|
20722
|
-
const quotedPattern = /["']([^"']+)["']/g;
|
|
20723
|
-
let quotedMatch;
|
|
20724
|
-
const quotedValues = [];
|
|
20725
|
-
while ((quotedMatch = quotedPattern.exec(paramText)) !== null) {
|
|
20726
|
-
quotedValues.push(quotedMatch[1]);
|
|
20727
|
-
}
|
|
20728
|
-
if (normalizedToolName === "Task") {
|
|
20729
|
-
if (!args.subagent_type) {
|
|
20730
|
-
const stMatch = paramText.match(/subagent_type\s*[=:]\s*["']?(\w+)["']?/i);
|
|
20731
|
-
if (stMatch) {
|
|
20732
|
-
args.subagent_type = stMatch[1];
|
|
20733
|
-
} else if (/explore|codebase|structure/i.test(paramText)) {
|
|
20734
|
-
args.subagent_type = "Explore";
|
|
20735
|
-
} else if (/plan|architect/i.test(paramText)) {
|
|
20736
|
-
args.subagent_type = "Plan";
|
|
20737
|
-
} else {
|
|
20738
|
-
args.subagent_type = "general-purpose";
|
|
20739
|
-
}
|
|
20740
|
-
}
|
|
20741
|
-
if (!args.prompt) {
|
|
20742
|
-
const toMatch = paramText.match(/\bto\s+(.+)/i);
|
|
20743
|
-
if (toMatch) {
|
|
20744
|
-
args.prompt = toMatch[1].trim();
|
|
20745
|
-
} else {
|
|
20746
|
-
args.prompt = paramText.trim();
|
|
20747
|
-
}
|
|
20748
|
-
}
|
|
20749
|
-
if (!args.description) {
|
|
20750
|
-
args.description = (args.prompt || paramText).substring(0, 50).trim();
|
|
20751
|
-
}
|
|
20752
|
-
} else if (normalizedToolName === "Read") {
|
|
20753
|
-
if (!args.file_path) {
|
|
20754
|
-
if (quotedValues.length > 0) {
|
|
20755
|
-
args.file_path = quotedValues[0];
|
|
20756
|
-
} else {
|
|
20757
|
-
const pathMatch = paramText.match(/(?:read|file)\s+([\/\w.-]+)/i);
|
|
20758
|
-
if (pathMatch) {
|
|
20759
|
-
args.file_path = pathMatch[1];
|
|
20760
|
-
}
|
|
20761
|
-
}
|
|
20762
|
-
}
|
|
20763
|
-
} else if (normalizedToolName === "Bash") {
|
|
20764
|
-
if (!args.command) {
|
|
20765
|
-
if (quotedValues.length > 0) {
|
|
20766
|
-
args.command = quotedValues[0];
|
|
20767
|
-
} else {
|
|
20768
|
-
const cmdMatch = paramText.match(/(?:run|execute)\s+(.+)/i);
|
|
20769
|
-
if (cmdMatch) {
|
|
20770
|
-
args.command = cmdMatch[1].trim();
|
|
20771
|
-
}
|
|
20772
|
-
}
|
|
20773
|
-
}
|
|
20774
|
-
if (args.command && !args.description) {
|
|
20775
|
-
args.description = `Run ${args.command.split(" ")[0]} command`;
|
|
20776
|
-
}
|
|
20777
|
-
} else if (normalizedToolName === "Grep" || normalizedToolName === "Glob") {
|
|
20778
|
-
if (!args.pattern) {
|
|
20779
|
-
if (quotedValues.length > 0) {
|
|
20780
|
-
args.pattern = quotedValues[0];
|
|
20781
|
-
} else {
|
|
20782
|
-
const searchMatch = paramText.match(/(?:search|find|look for)\s+(.+)/i);
|
|
20783
|
-
if (searchMatch) {
|
|
20784
|
-
args.pattern = searchMatch[1].trim();
|
|
20785
|
-
}
|
|
20786
|
-
}
|
|
20787
|
-
}
|
|
20788
|
-
}
|
|
20789
21298
|
if (Object.keys(args).length > 0) {
|
|
20790
21299
|
extracted.push({
|
|
20791
21300
|
name: normalizedToolName,
|
|
@@ -20796,139 +21305,7 @@ function extractToolCallsFromText(text, knownToolNames) {
|
|
|
20796
21305
|
}
|
|
20797
21306
|
}
|
|
20798
21307
|
}
|
|
20799
|
-
return keepOnlyRealTools(extracted, knownToolNames);
|
|
20800
|
-
}
|
|
20801
|
-
function inferMissingParameters(toolName, args, missingParams, context) {
|
|
20802
|
-
const inferred = { ...args };
|
|
20803
|
-
if (toolName === "Task") {
|
|
20804
|
-
const validSubagentTypes = [
|
|
20805
|
-
"general-purpose",
|
|
20806
|
-
"Explore",
|
|
20807
|
-
"Plan",
|
|
20808
|
-
"claude-code-guide",
|
|
20809
|
-
"code-analysis:detective",
|
|
20810
|
-
"feature-dev:code-architect",
|
|
20811
|
-
"feature-dev:code-explorer",
|
|
20812
|
-
"feature-dev:code-reviewer"
|
|
20813
|
-
];
|
|
20814
|
-
if (inferred.subagent_type) {
|
|
20815
|
-
const st = inferred.subagent_type.toLowerCase();
|
|
20816
|
-
if (st.includes("explore") || st.includes("codebase") || st.includes("file")) {
|
|
20817
|
-
inferred.subagent_type = "Explore";
|
|
20818
|
-
} else if (st.includes("plan") || st.includes("architect")) {
|
|
20819
|
-
inferred.subagent_type = "Plan";
|
|
20820
|
-
} else if (st.includes("analysis") || st.includes("analyz") || st.includes("config") || st.includes("git") || st.includes("test") || st.includes("doc") || st.includes("version")) {
|
|
20821
|
-
inferred.subagent_type = "general-purpose";
|
|
20822
|
-
} else if (!validSubagentTypes.includes(inferred.subagent_type)) {
|
|
20823
|
-
log(`[ToolRecovery] Unknown subagent_type "${inferred.subagent_type}", mapping to general-purpose`);
|
|
20824
|
-
inferred.subagent_type = "general-purpose";
|
|
20825
|
-
}
|
|
20826
|
-
}
|
|
20827
|
-
if (missingParams.includes("subagent_type") && !inferred.subagent_type) {
|
|
20828
|
-
inferred.subagent_type = "general-purpose";
|
|
20829
|
-
log("[ToolRecovery] Inferred subagent_type: general-purpose");
|
|
20830
|
-
}
|
|
20831
|
-
let extractedTask = "";
|
|
20832
|
-
if (context) {
|
|
20833
|
-
const patterns = [
|
|
20834
|
-
/(?:I(?:'ll| will| need to| want to| am going to)|Let me|Going to)\s+([^.!?\n]+)/i,
|
|
20835
|
-
/(?:help you|assist with)\s+([^.!?\n]+)/i,
|
|
20836
|
-
/(?:explore|search|find|look for|investigate)\s+([^.!?\n]+)/i,
|
|
20837
|
-
/(?:implement|create|build|add|fix|update)\s+([^.!?\n]+)/i
|
|
20838
|
-
];
|
|
20839
|
-
for (const pattern of patterns) {
|
|
20840
|
-
const match = context.match(pattern);
|
|
20841
|
-
if (match?.[1] && match[1].length > 10) {
|
|
20842
|
-
extractedTask = match[1].trim();
|
|
20843
|
-
log(`[ToolRecovery] Extracted task from context: "${extractedTask.substring(0, 50)}..."`);
|
|
20844
|
-
break;
|
|
20845
|
-
}
|
|
20846
|
-
}
|
|
20847
|
-
if (!extractedTask && context.length > 20) {
|
|
20848
|
-
const sentences = context.split(/[.!?\n]+/).filter((s) => s.trim().length > 15);
|
|
20849
|
-
if (sentences.length > 0) {
|
|
20850
|
-
extractedTask = sentences[sentences.length - 1].trim();
|
|
20851
|
-
}
|
|
20852
|
-
}
|
|
20853
|
-
}
|
|
20854
|
-
if (missingParams.includes("prompt") && !inferred.prompt) {
|
|
20855
|
-
if (inferred.query) {
|
|
20856
|
-
inferred.prompt = inferred.query;
|
|
20857
|
-
log(`[ToolRecovery] Mapped query -> prompt: "${inferred.query.substring(0, 50)}..."`);
|
|
20858
|
-
} else if (inferred.description && inferred.description !== "Execute task") {
|
|
20859
|
-
inferred.prompt = inferred.description;
|
|
20860
|
-
} else if (inferred.task) {
|
|
20861
|
-
inferred.prompt = inferred.task;
|
|
20862
|
-
} else if (extractedTask) {
|
|
20863
|
-
inferred.prompt = extractedTask;
|
|
20864
|
-
} else if (context && context.length > 20) {
|
|
20865
|
-
inferred.prompt = context.substring(0, 500).trim();
|
|
20866
|
-
}
|
|
20867
|
-
if (inferred.prompt) {
|
|
20868
|
-
log(`[ToolRecovery] Inferred prompt: "${inferred.prompt.substring(0, 50)}..."`);
|
|
20869
|
-
}
|
|
20870
|
-
}
|
|
20871
|
-
if (missingParams.includes("description") && !inferred.description) {
|
|
20872
|
-
if (inferred.prompt) {
|
|
20873
|
-
inferred.description = inferred.prompt.substring(0, 50).replace(/\s+/g, " ").trim();
|
|
20874
|
-
if (inferred.description.length < inferred.prompt.length) {
|
|
20875
|
-
inferred.description += "...";
|
|
20876
|
-
}
|
|
20877
|
-
} else if (extractedTask) {
|
|
20878
|
-
inferred.description = extractedTask.substring(0, 50).trim();
|
|
20879
|
-
} else {
|
|
20880
|
-
inferred.description = "Execute task";
|
|
20881
|
-
}
|
|
20882
|
-
log(`[ToolRecovery] Inferred description: ${inferred.description}`);
|
|
20883
|
-
}
|
|
20884
|
-
}
|
|
20885
|
-
if (toolName === "Bash") {
|
|
20886
|
-
if (missingParams.includes("command") && !inferred.command) {
|
|
20887
|
-
inferred.command = inferred.cmd || inferred.shell || inferred.script || "";
|
|
20888
|
-
}
|
|
20889
|
-
if (missingParams.includes("description") && !inferred.description) {
|
|
20890
|
-
if (inferred.command) {
|
|
20891
|
-
const cmd = inferred.command.split(" ")[0];
|
|
20892
|
-
inferred.description = `Run ${cmd} command`;
|
|
20893
|
-
}
|
|
20894
|
-
}
|
|
20895
|
-
}
|
|
20896
|
-
if (toolName === "Read") {
|
|
20897
|
-
if (missingParams.includes("file_path") && !inferred.file_path) {
|
|
20898
|
-
inferred.file_path = inferred.path || inferred.file || inferred.filename || "";
|
|
20899
|
-
}
|
|
20900
|
-
}
|
|
20901
|
-
if (toolName === "Write") {
|
|
20902
|
-
if (missingParams.includes("file_path") && !inferred.file_path) {
|
|
20903
|
-
inferred.file_path = inferred.path || inferred.file || inferred.filename || "";
|
|
20904
|
-
}
|
|
20905
|
-
if (missingParams.includes("content") && !inferred.content) {
|
|
20906
|
-
inferred.content = inferred.text || inferred.data || inferred.body || "";
|
|
20907
|
-
}
|
|
20908
|
-
}
|
|
20909
|
-
if (toolName === "Grep") {
|
|
20910
|
-
if (missingParams.includes("pattern") && !inferred.pattern) {
|
|
20911
|
-
inferred.pattern = inferred.query || inferred.search || inferred.regex || "";
|
|
20912
|
-
}
|
|
20913
|
-
}
|
|
20914
|
-
if (toolName === "Glob") {
|
|
20915
|
-
if (missingParams.includes("pattern") && !inferred.pattern) {
|
|
20916
|
-
inferred.pattern = inferred.glob || inferred.path || inferred.search || "**/*";
|
|
20917
|
-
}
|
|
20918
|
-
}
|
|
20919
|
-
if (toolName === "ToolSearch") {
|
|
20920
|
-
if (missingParams.includes("max_results") && inferred.max_results === undefined) {
|
|
20921
|
-
inferred.max_results = 5;
|
|
20922
|
-
log("[ToolRecovery] Inferred max_results: 5 (default)");
|
|
20923
|
-
}
|
|
20924
|
-
if (missingParams.includes("query") && !inferred.query) {
|
|
20925
|
-
inferred.query = inferred.search || inferred.keyword || inferred.tool || "";
|
|
20926
|
-
if (inferred.query) {
|
|
20927
|
-
log(`[ToolRecovery] Inferred ToolSearch query: "${inferred.query}"`);
|
|
20928
|
-
}
|
|
20929
|
-
}
|
|
20930
|
-
}
|
|
20931
|
-
return inferred;
|
|
21308
|
+
return keepOnlyRealTools(extracted, knownToolNames, decodeToolName);
|
|
20932
21309
|
}
|
|
20933
21310
|
function validateAndRepairToolCall(toolName, argsStr, toolSchemas, textContent) {
|
|
20934
21311
|
const schema = toolSchemas.find((t) => t.name === toolName);
|
|
@@ -20940,7 +21317,7 @@ function validateAndRepairToolCall(toolName, argsStr, toolSchemas, textContent)
|
|
|
20940
21317
|
parsedArgs = argsStr ? JSON.parse(argsStr) : {};
|
|
20941
21318
|
} catch (e) {
|
|
20942
21319
|
if (textContent) {
|
|
20943
|
-
const extracted = extractToolCallsFromText(textContent);
|
|
21320
|
+
const extracted = extractToolCallsFromText(textContent, toolSchemas.map((t) => t.name), toolSchemas);
|
|
20944
21321
|
const matching = extracted.find((tc) => tc.name === toolName);
|
|
20945
21322
|
if (matching) {
|
|
20946
21323
|
parsedArgs = matching.arguments;
|
|
@@ -20948,25 +21325,33 @@ function validateAndRepairToolCall(toolName, argsStr, toolSchemas, textContent)
|
|
|
20948
21325
|
}
|
|
20949
21326
|
}
|
|
20950
21327
|
}
|
|
20951
|
-
const
|
|
20952
|
-
const
|
|
20953
|
-
|
|
20954
|
-
|
|
21328
|
+
const input = schema.input_schema;
|
|
21329
|
+
const renamed = renameToDeclaredKeys(input, parsedArgs);
|
|
21330
|
+
const defaulted = applySchemaDefaults(input, renamed.args);
|
|
21331
|
+
const coerced = coerceToSchema(input, defaulted.args);
|
|
21332
|
+
const args = coerced.args;
|
|
21333
|
+
const repaired = renamed.renamed.length > 0 || defaulted.applied.length > 0;
|
|
21334
|
+
if (repaired) {
|
|
21335
|
+
log(`[ToolRecovery] ${toolName}: applied schema defaults [${defaulted.applied}] ` + `and key renames [${renamed.renamed}] \u2014 nothing was invented`);
|
|
21336
|
+
}
|
|
21337
|
+
if (coerced.coerced.length > 0) {
|
|
21338
|
+
log(`[ToolRecovery] ${toolName}: coerced to declared types [${coerced.coerced}]`);
|
|
20955
21339
|
}
|
|
20956
|
-
const
|
|
20957
|
-
|
|
20958
|
-
|
|
20959
|
-
log(`[ToolRecovery] Successfully repaired tool call ${toolName}`);
|
|
20960
|
-
return { valid: true, args: repairedArgs, repaired: true, missingParams: [] };
|
|
21340
|
+
const missingParams = missingRequired(input, args);
|
|
21341
|
+
if (missingParams.length === 0) {
|
|
21342
|
+
return { valid: true, args, repaired, missingParams: [] };
|
|
20961
21343
|
}
|
|
20962
|
-
return { valid: false, args
|
|
21344
|
+
return { valid: false, args, repaired: false, missingParams };
|
|
20963
21345
|
}
|
|
20964
|
-
var FUNCTION_TAG_SOURCE, FUNCTION_TAG_PRESENT;
|
|
21346
|
+
var FUNCTION_TAG_SOURCE, FUNCTION_TAG_PRESENT, FUNCTION_TAG_AT_CURSOR, PARAMETER_TAG_AT_CURSOR;
|
|
20965
21347
|
var init_tool_call_recovery = __esm(() => {
|
|
20966
21348
|
init_tool_name_utils();
|
|
20967
21349
|
init_logger();
|
|
21350
|
+
init_schema_validate();
|
|
20968
21351
|
FUNCTION_TAG_SOURCE = `<function=(${TOOL_NAME_SOURCE})>([\\s\\S]*?)(?=<function=|$)`;
|
|
20969
21352
|
FUNCTION_TAG_PRESENT = new RegExp(`<function=${TOOL_NAME_SOURCE}>`);
|
|
21353
|
+
FUNCTION_TAG_AT_CURSOR = new RegExp(`<function=(${TOOL_NAME_SOURCE})>`, "y");
|
|
21354
|
+
PARAMETER_TAG_AT_CURSOR = /<parameter=([^>\s]+)>/y;
|
|
20970
21355
|
});
|
|
20971
21356
|
|
|
20972
21357
|
// src/handlers/shared/web-search-detector.ts
|
|
@@ -20983,11 +21368,218 @@ var init_web_search_detector = __esm(() => {
|
|
|
20983
21368
|
WEB_SEARCH_NAMES = new Set(["web_search", "brave_web_search", "tavily_search"]);
|
|
20984
21369
|
});
|
|
20985
21370
|
|
|
21371
|
+
// src/handlers/shared/stream-parsers/block-writer.ts
|
|
21372
|
+
function createBlockWriter(send) {
|
|
21373
|
+
let nextIndex = 0;
|
|
21374
|
+
let openRef = null;
|
|
21375
|
+
let anyBlockEmitted = false;
|
|
21376
|
+
const emittedToolRefs = [];
|
|
21377
|
+
const stopped = new Set;
|
|
21378
|
+
const describe = (ref) => ref ? `${ref.kind}@${ref.index}` : "none";
|
|
21379
|
+
const spendableIndex = (requested, kind) => {
|
|
21380
|
+
if (requested === undefined)
|
|
21381
|
+
return nextIndex++;
|
|
21382
|
+
if (!stopped.has(requested))
|
|
21383
|
+
return requested;
|
|
21384
|
+
const replacement = nextIndex++;
|
|
21385
|
+
log(`[BlockWriter] open error: index ${requested} was already stopped; ${kind} block re-indexed to ${replacement}`);
|
|
21386
|
+
return replacement;
|
|
21387
|
+
};
|
|
21388
|
+
const closeCurrent = () => {
|
|
21389
|
+
if (!openRef)
|
|
21390
|
+
return;
|
|
21391
|
+
send("content_block_stop", { type: "content_block_stop", index: openRef.index });
|
|
21392
|
+
stopped.add(openRef.index);
|
|
21393
|
+
openRef = null;
|
|
21394
|
+
};
|
|
21395
|
+
const start = (ref, contentBlock) => {
|
|
21396
|
+
send("content_block_start", {
|
|
21397
|
+
type: "content_block_start",
|
|
21398
|
+
index: ref.index,
|
|
21399
|
+
content_block: contentBlock
|
|
21400
|
+
});
|
|
21401
|
+
openRef = ref;
|
|
21402
|
+
anyBlockEmitted = true;
|
|
21403
|
+
return ref;
|
|
21404
|
+
};
|
|
21405
|
+
const writer = {
|
|
21406
|
+
openText(opts) {
|
|
21407
|
+
if (openRef?.kind === "text") {
|
|
21408
|
+
if (opts?.index !== undefined && opts.index !== openRef.index) {
|
|
21409
|
+
log(`[BlockWriter] reusing open text block @${openRef.index}; reserved index ${opts.index} goes unused`);
|
|
21410
|
+
}
|
|
21411
|
+
return openRef;
|
|
21412
|
+
}
|
|
21413
|
+
closeCurrent();
|
|
21414
|
+
const index = spendableIndex(opts?.index, "text");
|
|
21415
|
+
return start({ index, kind: "text" }, { type: "text", text: "" });
|
|
21416
|
+
},
|
|
21417
|
+
openThinking() {
|
|
21418
|
+
if (openRef?.kind === "thinking")
|
|
21419
|
+
return openRef;
|
|
21420
|
+
closeCurrent();
|
|
21421
|
+
return start({ index: nextIndex++, kind: "thinking" }, { type: "thinking", thinking: "" });
|
|
21422
|
+
},
|
|
21423
|
+
openTool({ id, name, index }) {
|
|
21424
|
+
closeCurrent();
|
|
21425
|
+
const ref = {
|
|
21426
|
+
index: spendableIndex(index, "tool_use"),
|
|
21427
|
+
kind: "tool_use",
|
|
21428
|
+
toolId: id
|
|
21429
|
+
};
|
|
21430
|
+
start(ref, { type: "tool_use", id, name, input: {} });
|
|
21431
|
+
emittedToolRefs.push(ref);
|
|
21432
|
+
return ref;
|
|
21433
|
+
},
|
|
21434
|
+
append(ref, payload) {
|
|
21435
|
+
if (!openRef || openRef.index !== ref.index || openRef.kind !== ref.kind) {
|
|
21436
|
+
log(`[BlockWriter] append error: ${describe(ref)} is not the open block (open=${describe(openRef)}); ${payload.length} chars withheld for the caller to handle`);
|
|
21437
|
+
return false;
|
|
21438
|
+
}
|
|
21439
|
+
const delta = ref.kind === "text" ? { type: "text_delta", text: payload } : ref.kind === "thinking" ? { type: "thinking_delta", thinking: payload } : { type: "input_json_delta", partial_json: payload };
|
|
21440
|
+
send("content_block_delta", { type: "content_block_delta", index: ref.index, delta });
|
|
21441
|
+
return true;
|
|
21442
|
+
},
|
|
21443
|
+
close(ref) {
|
|
21444
|
+
if (openRef && openRef.index === ref.index && openRef.kind === ref.kind) {
|
|
21445
|
+
closeCurrent();
|
|
21446
|
+
return;
|
|
21447
|
+
}
|
|
21448
|
+
if (stopped.has(ref.index))
|
|
21449
|
+
return;
|
|
21450
|
+
log(`[BlockWriter] close error: ${describe(ref)} was never opened and is not stopped (open=${describe(openRef)})`);
|
|
21451
|
+
},
|
|
21452
|
+
closeCurrent,
|
|
21453
|
+
reserve() {
|
|
21454
|
+
return nextIndex++;
|
|
21455
|
+
},
|
|
21456
|
+
get openRef() {
|
|
21457
|
+
return openRef;
|
|
21458
|
+
},
|
|
21459
|
+
get anyBlockEmitted() {
|
|
21460
|
+
return anyBlockEmitted;
|
|
21461
|
+
},
|
|
21462
|
+
get emittedToolRefs() {
|
|
21463
|
+
return emittedToolRefs;
|
|
21464
|
+
}
|
|
21465
|
+
};
|
|
21466
|
+
return writer;
|
|
21467
|
+
}
|
|
21468
|
+
var init_block_writer = __esm(() => {
|
|
21469
|
+
init_logger();
|
|
21470
|
+
});
|
|
21471
|
+
|
|
20986
21472
|
// src/handlers/shared/stream-parsers/message-start-usage.ts
|
|
20987
21473
|
function messageStartUsage(priorInputTokens) {
|
|
20988
21474
|
return {
|
|
20989
21475
|
input_tokens: priorInputTokens && priorInputTokens > 0 ? priorInputTokens : 100,
|
|
20990
|
-
output_tokens: 1
|
|
21476
|
+
output_tokens: 1,
|
|
21477
|
+
cache_read_input_tokens: 0,
|
|
21478
|
+
cache_creation_input_tokens: 0
|
|
21479
|
+
};
|
|
21480
|
+
}
|
|
21481
|
+
|
|
21482
|
+
// src/handlers/shared/stream-parsers/think-tag-splitter.ts
|
|
21483
|
+
function createThinkTagSplitter() {
|
|
21484
|
+
let phase = "deciding";
|
|
21485
|
+
let pending = "";
|
|
21486
|
+
let openArmed = true;
|
|
21487
|
+
const heldSuffixLength = (s) => {
|
|
21488
|
+
for (let n = Math.min(CLOSE.length - 1, s.length);n > 0; n--) {
|
|
21489
|
+
if (CLOSE.startsWith(s.slice(s.length - n)))
|
|
21490
|
+
return n;
|
|
21491
|
+
}
|
|
21492
|
+
return 0;
|
|
21493
|
+
};
|
|
21494
|
+
const consumeThinking = (chunk) => {
|
|
21495
|
+
pending += chunk;
|
|
21496
|
+
const at = pending.indexOf(CLOSE);
|
|
21497
|
+
if (at >= 0) {
|
|
21498
|
+
const thinking = pending.slice(0, at);
|
|
21499
|
+
const text = pending.slice(at + CLOSE.length);
|
|
21500
|
+
pending = "";
|
|
21501
|
+
phase = "passthrough";
|
|
21502
|
+
return { thinking, text };
|
|
21503
|
+
}
|
|
21504
|
+
const hold = heldSuffixLength(pending);
|
|
21505
|
+
const thinking = pending.slice(0, pending.length - hold);
|
|
21506
|
+
pending = hold === 0 ? "" : pending.slice(pending.length - hold);
|
|
21507
|
+
return { thinking, text: "" };
|
|
21508
|
+
};
|
|
21509
|
+
const decide = (isFlush) => {
|
|
21510
|
+
const lead = pending.replace(/^\s+/, "");
|
|
21511
|
+
const releaseAsText = () => {
|
|
21512
|
+
phase = "passthrough";
|
|
21513
|
+
const text = pending;
|
|
21514
|
+
pending = "";
|
|
21515
|
+
return { thinking: "", text };
|
|
21516
|
+
};
|
|
21517
|
+
if (lead === "")
|
|
21518
|
+
return isFlush ? releaseAsText() : EMPTY;
|
|
21519
|
+
if (openArmed && lead.startsWith(OPEN)) {
|
|
21520
|
+
phase = "thinking";
|
|
21521
|
+
pending = "";
|
|
21522
|
+
return consumeThinking(lead.slice(OPEN.length));
|
|
21523
|
+
}
|
|
21524
|
+
if (lead.startsWith(CLOSE)) {
|
|
21525
|
+
phase = "passthrough";
|
|
21526
|
+
pending = "";
|
|
21527
|
+
return { thinking: "", text: lead.slice(CLOSE.length) };
|
|
21528
|
+
}
|
|
21529
|
+
if (openArmed && OPEN.startsWith(lead) || CLOSE.startsWith(lead)) {
|
|
21530
|
+
return isFlush ? releaseAsText() : EMPTY;
|
|
21531
|
+
}
|
|
21532
|
+
return releaseAsText();
|
|
21533
|
+
};
|
|
21534
|
+
return {
|
|
21535
|
+
push(chunk) {
|
|
21536
|
+
if (!chunk)
|
|
21537
|
+
return EMPTY;
|
|
21538
|
+
if (phase === "passthrough")
|
|
21539
|
+
return { thinking: "", text: chunk };
|
|
21540
|
+
if (phase === "thinking")
|
|
21541
|
+
return consumeThinking(chunk);
|
|
21542
|
+
pending += chunk;
|
|
21543
|
+
return decide(false);
|
|
21544
|
+
},
|
|
21545
|
+
flush() {
|
|
21546
|
+
if (phase === "passthrough")
|
|
21547
|
+
return EMPTY;
|
|
21548
|
+
if (phase === "thinking") {
|
|
21549
|
+
const thinking = pending;
|
|
21550
|
+
pending = "";
|
|
21551
|
+
return { thinking, text: "" };
|
|
21552
|
+
}
|
|
21553
|
+
return decide(true);
|
|
21554
|
+
},
|
|
21555
|
+
disarmOpen() {
|
|
21556
|
+
openArmed = false;
|
|
21557
|
+
},
|
|
21558
|
+
get inThinking() {
|
|
21559
|
+
return phase === "thinking";
|
|
21560
|
+
}
|
|
21561
|
+
};
|
|
21562
|
+
}
|
|
21563
|
+
var OPEN = "<think>", CLOSE = "</think>", EMPTY;
|
|
21564
|
+
var init_think_tag_splitter = __esm(() => {
|
|
21565
|
+
EMPTY = { thinking: "", text: "" };
|
|
21566
|
+
});
|
|
21567
|
+
|
|
21568
|
+
// src/handlers/shared/stream-parsers/usage-cache-split.ts
|
|
21569
|
+
function nonNegativeInt(value) {
|
|
21570
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
|
|
21571
|
+
}
|
|
21572
|
+
function splitPromptTokens(usage) {
|
|
21573
|
+
const u = usage ?? {};
|
|
21574
|
+
const promptTokens = nonNegativeInt(u.prompt_tokens);
|
|
21575
|
+
const details = u.prompt_tokens_details ?? {};
|
|
21576
|
+
const cacheReadTokens = Math.min(nonNegativeInt(details.cached_tokens), promptTokens);
|
|
21577
|
+
const cacheCreationTokens = Math.min(nonNegativeInt(details.cache_write_tokens), promptTokens - cacheReadTokens);
|
|
21578
|
+
return {
|
|
21579
|
+
promptTokens,
|
|
21580
|
+
inputTokens: promptTokens - cacheReadTokens - cacheCreationTokens,
|
|
21581
|
+
cacheReadTokens,
|
|
21582
|
+
cacheCreationTokens
|
|
20991
21583
|
};
|
|
20992
21584
|
}
|
|
20993
21585
|
|
|
@@ -21014,12 +21606,9 @@ function createStreamingState() {
|
|
|
21014
21606
|
return {
|
|
21015
21607
|
usage: null,
|
|
21016
21608
|
finalized: false,
|
|
21017
|
-
textStarted: false,
|
|
21018
|
-
textIdx: -1,
|
|
21019
|
-
reasoningStarted: false,
|
|
21020
|
-
reasoningIdx: -1,
|
|
21021
|
-
curIdx: 0,
|
|
21022
21609
|
tools: new Map,
|
|
21610
|
+
pendingToolArgs: new Map,
|
|
21611
|
+
pendingToolName: new Map,
|
|
21023
21612
|
toolIds: new Set,
|
|
21024
21613
|
lastActivity: Date.now(),
|
|
21025
21614
|
accumulatedText: "",
|
|
@@ -21066,6 +21655,24 @@ data: ${JSON.stringify(d)}
|
|
|
21066
21655
|
};
|
|
21067
21656
|
const msgId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
21068
21657
|
const state = createStreamingState();
|
|
21658
|
+
const writer = createBlockWriter(send);
|
|
21659
|
+
const thinkSplitter = createThinkTagSplitter();
|
|
21660
|
+
const emitSplitContent = ({ thinking, text }) => {
|
|
21661
|
+
if (thinking) {
|
|
21662
|
+
behavior?.onAssistantText?.(thinking, "reasoning");
|
|
21663
|
+
writer.append(writer.openThinking(), thinking);
|
|
21664
|
+
}
|
|
21665
|
+
if (!text)
|
|
21666
|
+
return;
|
|
21667
|
+
state.accumulatedText += text;
|
|
21668
|
+
const hasStructuredToolPattern = hasExtractableFunctionTag(state.accumulatedText) || /\{\s*"(?:name|tool)"\s*:\s*"(?:Task|Read|Write|Edit|Bash|Grep|Glob)"/i.test(state.accumulatedText) || /<tool_call>/.test(state.accumulatedText);
|
|
21669
|
+
const shouldHoldBack = hasStructuredToolPattern && state.accumulatedText.length < 1000;
|
|
21670
|
+
if (shouldHoldBack) {
|
|
21671
|
+
log(`[Streaming] Text held back (structured tool pattern): ${state.accumulatedText.length} chars accumulated`);
|
|
21672
|
+
return;
|
|
21673
|
+
}
|
|
21674
|
+
writer.append(writer.openText(), text);
|
|
21675
|
+
};
|
|
21069
21676
|
send("message_start", {
|
|
21070
21677
|
type: "message_start",
|
|
21071
21678
|
message: {
|
|
@@ -21110,67 +21717,50 @@ data: ${JSON.stringify(d)}
|
|
|
21110
21717
|
}
|
|
21111
21718
|
state.finalized = true;
|
|
21112
21719
|
try {
|
|
21720
|
+
emitSplitContent(thinkSplitter.flush());
|
|
21721
|
+
for (const [idx, pending] of state.pendingToolArgs) {
|
|
21722
|
+
log(`[Streaming] Tool argument error: discarding ${pending.length} buffered chars for tool_calls index ${idx} \u2014 function.name never arrived`);
|
|
21723
|
+
}
|
|
21724
|
+
state.pendingToolArgs.clear();
|
|
21113
21725
|
if (state.accumulatedText.length > 0) {
|
|
21114
21726
|
const preview = state.accumulatedText.slice(0, 500).replace(/\n/g, "\\n");
|
|
21115
21727
|
log(`[Streaming] Accumulated text (${state.accumulatedText.length} chars): ${preview}...`);
|
|
21116
21728
|
}
|
|
21117
|
-
const textToolCalls = state.tools.size > 0 ? [] : extractToolCallsFromText(state.accumulatedText, toolSchemas?.map((t) => t?.name).filter((n) => !!n));
|
|
21729
|
+
const textToolCalls = state.tools.size > 0 ? [] : extractToolCallsFromText(state.accumulatedText, toolSchemas?.map((t) => t?.name).filter((n) => !!n), toolSchemas, toolNameMap ? (name) => toolNameMap.get(name) ?? name : undefined);
|
|
21118
21730
|
if (state.tools.size > 0 && state.accumulatedText.length > 0) {
|
|
21119
21731
|
log(`[Streaming] Skipping text-based tool extraction: ${state.tools.size} structured tool call(s) already present`);
|
|
21120
21732
|
}
|
|
21121
21733
|
log(`[Streaming] Text-based tool calls found: ${textToolCalls.length}`);
|
|
21122
|
-
|
|
21734
|
+
const producedContent = state.accumulatedText.length > 0 || writer.anyBlockEmitted || state.tools.size > 0 || textToolCalls.length > 0;
|
|
21735
|
+
const toolInFlight = writer.emittedToolRefs.length > 0 || Array.from(state.tools.values()).some((t) => !t.closed && (t.started || t.buffered)) || textToolCalls.length > 0;
|
|
21736
|
+
const ending = reason === "error" ? "failure" : state.finishReason !== null || !producedContent ? "success" : toolInFlight ? "failure" : "silent-truncation";
|
|
21737
|
+
if (ending !== "success") {
|
|
21738
|
+
log(`[Streaming] Stream ending error: reason=${reason} finish_reason=${state.finishReason ?? "null"} content=${producedContent} tool_in_flight=${toolInFlight} \u2192 ${ending}`);
|
|
21739
|
+
}
|
|
21740
|
+
const emitToolCalls = ending !== "failure";
|
|
21741
|
+
if (textToolCalls.length > 0 && !emitToolCalls) {
|
|
21742
|
+
log(`[Streaming] Suppressing ${textToolCalls.length} text-recovered tool call(s): the turn ended in failure`);
|
|
21743
|
+
} else if (textToolCalls.length > 0) {
|
|
21123
21744
|
log(`[Streaming] Found ${textToolCalls.length} text-based tool call(s), converting to structured format`);
|
|
21124
|
-
if (state.textStarted) {
|
|
21125
|
-
send("content_block_stop", { type: "content_block_stop", index: state.textIdx });
|
|
21126
|
-
state.textStarted = false;
|
|
21127
|
-
}
|
|
21128
21745
|
for (const tc of textToolCalls) {
|
|
21129
|
-
const toolIdx =
|
|
21746
|
+
const toolIdx = writer.reserve();
|
|
21130
21747
|
const toolId = `tool_${Date.now()}_${toolIdx}`;
|
|
21131
|
-
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
content_block: { type: "tool_use", id: toolId, name: tc.name }
|
|
21135
|
-
});
|
|
21136
|
-
send("content_block_delta", {
|
|
21137
|
-
type: "content_block_delta",
|
|
21138
|
-
index: toolIdx,
|
|
21139
|
-
delta: {
|
|
21140
|
-
type: "input_json_delta",
|
|
21141
|
-
partial_json: repairArgs(tc.name, JSON.stringify(tc.arguments))
|
|
21142
|
-
}
|
|
21143
|
-
});
|
|
21144
|
-
send("content_block_stop", { type: "content_block_stop", index: toolIdx });
|
|
21748
|
+
const ref = writer.openTool({ id: toolId, name: tc.name, index: toolIdx });
|
|
21749
|
+
writer.append(ref, repairArgs(tc.name, JSON.stringify(tc.arguments)));
|
|
21750
|
+
writer.close(ref);
|
|
21145
21751
|
}
|
|
21146
21752
|
}
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
}
|
|
21150
|
-
if (state.textStarted) {
|
|
21151
|
-
send("content_block_stop", { type: "content_block_stop", index: state.textIdx });
|
|
21152
|
-
}
|
|
21153
|
-
for (const t of Array.from(state.tools.values())) {
|
|
21753
|
+
writer.closeCurrent();
|
|
21754
|
+
for (const t of emitToolCalls ? Array.from(state.tools.values()) : []) {
|
|
21154
21755
|
if (!t.closed && t.buffered && !t.started) {
|
|
21155
21756
|
if (toolSchemas && toolSchemas.length > 0) {
|
|
21156
21757
|
const validation = validateToolArguments(t.name, t.arguments, toolSchemas, state.accumulatedText);
|
|
21157
21758
|
if (validation.valid || validation.repaired && validation.repairedArgs) {
|
|
21158
21759
|
const argsJson = repairArgs(t.name, JSON.stringify(validation.repaired ? validation.repairedArgs : validation.parsedArgs));
|
|
21159
21760
|
log(`[Streaming] Sending buffered tool call (finish_reason!=tool_calls): ${t.name} with args: ${argsJson}`);
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
content_block: { type: "tool_use", id: t.id, name: t.name }
|
|
21164
|
-
});
|
|
21165
|
-
send("content_block_delta", {
|
|
21166
|
-
type: "content_block_delta",
|
|
21167
|
-
index: t.blockIndex,
|
|
21168
|
-
delta: { type: "input_json_delta", partial_json: argsJson }
|
|
21169
|
-
});
|
|
21170
|
-
send("content_block_stop", {
|
|
21171
|
-
type: "content_block_stop",
|
|
21172
|
-
index: t.blockIndex
|
|
21173
|
-
});
|
|
21761
|
+
t.ref = writer.openTool({ id: t.id, name: t.name, index: t.blockIndex });
|
|
21762
|
+
writer.append(t.ref, argsJson);
|
|
21763
|
+
writer.close(t.ref);
|
|
21174
21764
|
t.started = true;
|
|
21175
21765
|
t.closed = true;
|
|
21176
21766
|
} else {
|
|
@@ -21180,20 +21770,9 @@ data: ${JSON.stringify(d)}
|
|
|
21180
21770
|
} else {
|
|
21181
21771
|
const argsJson = repairArgs(t.name, t.arguments || "{}");
|
|
21182
21772
|
log(`[Streaming] Sending buffered tool call (no validation): ${t.name} with args: ${argsJson}`);
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
content_block: { type: "tool_use", id: t.id, name: t.name }
|
|
21187
|
-
});
|
|
21188
|
-
send("content_block_delta", {
|
|
21189
|
-
type: "content_block_delta",
|
|
21190
|
-
index: t.blockIndex,
|
|
21191
|
-
delta: { type: "input_json_delta", partial_json: argsJson }
|
|
21192
|
-
});
|
|
21193
|
-
send("content_block_stop", {
|
|
21194
|
-
type: "content_block_stop",
|
|
21195
|
-
index: t.blockIndex
|
|
21196
|
-
});
|
|
21773
|
+
t.ref = writer.openTool({ id: t.id, name: t.name, index: t.blockIndex });
|
|
21774
|
+
writer.append(t.ref, argsJson);
|
|
21775
|
+
writer.close(t.ref);
|
|
21197
21776
|
t.started = true;
|
|
21198
21777
|
t.closed = true;
|
|
21199
21778
|
}
|
|
@@ -21201,28 +21780,41 @@ data: ${JSON.stringify(d)}
|
|
|
21201
21780
|
}
|
|
21202
21781
|
for (const t of Array.from(state.tools.values())) {
|
|
21203
21782
|
if (t.started && !t.closed) {
|
|
21204
|
-
|
|
21783
|
+
if (t.ref)
|
|
21784
|
+
writer.close(t.ref);
|
|
21205
21785
|
t.closed = true;
|
|
21206
21786
|
}
|
|
21207
21787
|
}
|
|
21208
21788
|
if (middlewareManager) {
|
|
21209
21789
|
await middlewareManager.afterStreamComplete(target, streamMetadata);
|
|
21210
21790
|
}
|
|
21211
|
-
if (
|
|
21212
|
-
|
|
21791
|
+
if (ending === "failure") {
|
|
21792
|
+
const message = err ?? "Upstream stream ended with no finish_reason while a tool call was in flight. " + "The tool call is incomplete and was not dispatched.";
|
|
21793
|
+
send("error", { type: "error", error: { type: "api_error", message } });
|
|
21213
21794
|
} else {
|
|
21214
21795
|
const hasStructuredTools = Array.from(state.tools.values()).some((t) => t.started);
|
|
21215
|
-
const truncated = state.finishReason === "length";
|
|
21796
|
+
const truncated = state.finishReason === "length" || ending === "silent-truncation";
|
|
21216
21797
|
const refused = state.finishReason === "content_filter";
|
|
21217
21798
|
const stopReason = refused ? "refusal" : truncated ? "max_tokens" : textToolCalls.length > 0 || hasStructuredTools ? "tool_use" : "end_turn";
|
|
21218
21799
|
if (truncated || refused) {
|
|
21219
21800
|
log(`[Streaming] Upstream finish_reason=${state.finishReason} \u2192 stop_reason=${stopReason} (${state.accumulatedText.length} chars produced)`);
|
|
21220
21801
|
}
|
|
21802
|
+
if (stopReason === "end_turn" && !writer.anyBlockEmitted) {
|
|
21803
|
+
log(`[Streaming] Contentless turn error: end_turn with no content block emitted (finish_reason=${state.finishReason ?? "null"}) \u2014 emitting an empty text block`);
|
|
21804
|
+
writer.close(writer.openText());
|
|
21805
|
+
}
|
|
21806
|
+
const split = splitPromptTokens(state.usage);
|
|
21807
|
+
const fullyCached = split.promptTokens > 0 && split.inputTokens === 0;
|
|
21808
|
+
const wireInput = fullyCached ? split.promptTokens : split.inputTokens;
|
|
21809
|
+
const wireCacheRead = fullyCached ? 0 : split.cacheReadTokens;
|
|
21810
|
+
const wireCacheCreation = fullyCached ? 0 : split.cacheCreationTokens;
|
|
21221
21811
|
send("message_delta", {
|
|
21222
21812
|
type: "message_delta",
|
|
21223
21813
|
delta: { stop_reason: stopReason, stop_sequence: null },
|
|
21224
21814
|
usage: {
|
|
21225
|
-
|
|
21815
|
+
input_tokens: wireInput,
|
|
21816
|
+
cache_read_input_tokens: wireCacheRead,
|
|
21817
|
+
cache_creation_input_tokens: wireCacheCreation,
|
|
21226
21818
|
output_tokens: state.usage?.completion_tokens || 0
|
|
21227
21819
|
}
|
|
21228
21820
|
});
|
|
@@ -21232,7 +21824,11 @@ data: ${JSON.stringify(d)}
|
|
|
21232
21824
|
if (onTokenUpdate) {
|
|
21233
21825
|
if (state.usage) {
|
|
21234
21826
|
log(`[Streaming] Final usage: prompt=${state.usage.prompt_tokens || 0}, completion=${state.usage.completion_tokens || 0}`);
|
|
21235
|
-
|
|
21827
|
+
const costSplit = splitPromptTokens(state.usage);
|
|
21828
|
+
onTokenUpdate(state.usage.prompt_tokens || 0, state.usage.completion_tokens || 0, {
|
|
21829
|
+
cacheReadTokens: costSplit.cacheReadTokens,
|
|
21830
|
+
cacheCreationTokens: costSplit.cacheCreationTokens
|
|
21831
|
+
});
|
|
21236
21832
|
} else {
|
|
21237
21833
|
const estimatedOutputTokens = Math.ceil(state.accumulatedText.length / 4);
|
|
21238
21834
|
log(`[Streaming] No usage data from provider, estimating: ~${estimatedOutputTokens} output tokens`);
|
|
@@ -21287,22 +21883,10 @@ data: ${JSON.stringify(d)}
|
|
|
21287
21883
|
}
|
|
21288
21884
|
const reasoningText = delta.reasoning_content || delta.reasoning;
|
|
21289
21885
|
if (reasoningText) {
|
|
21886
|
+
thinkSplitter.disarmOpen();
|
|
21290
21887
|
behavior?.onAssistantText?.(reasoningText, "reasoning");
|
|
21291
21888
|
state.lastActivity = Date.now();
|
|
21292
|
-
|
|
21293
|
-
state.reasoningIdx = state.curIdx++;
|
|
21294
|
-
send("content_block_start", {
|
|
21295
|
-
type: "content_block_start",
|
|
21296
|
-
index: state.reasoningIdx,
|
|
21297
|
-
content_block: { type: "thinking", thinking: "" }
|
|
21298
|
-
});
|
|
21299
|
-
state.reasoningStarted = true;
|
|
21300
|
-
}
|
|
21301
|
-
send("content_block_delta", {
|
|
21302
|
-
type: "content_block_delta",
|
|
21303
|
-
index: state.reasoningIdx,
|
|
21304
|
-
delta: { type: "thinking_delta", thinking: reasoningText }
|
|
21305
|
-
});
|
|
21889
|
+
writer.append(writer.openThinking(), reasoningText);
|
|
21306
21890
|
}
|
|
21307
21891
|
const txt = delta.content || "";
|
|
21308
21892
|
if (txt)
|
|
@@ -21310,42 +21894,13 @@ data: ${JSON.stringify(d)}
|
|
|
21310
21894
|
log(`[Streaming] Text chunk: "${txt.substring(0, 30).replace(/\n/g, "\\n")}" (${txt.length} chars)`);
|
|
21311
21895
|
if (txt) {
|
|
21312
21896
|
state.lastActivity = Date.now();
|
|
21313
|
-
if (state.reasoningStarted) {
|
|
21314
|
-
send("content_block_stop", {
|
|
21315
|
-
type: "content_block_stop",
|
|
21316
|
-
index: state.reasoningIdx
|
|
21317
|
-
});
|
|
21318
|
-
state.reasoningStarted = false;
|
|
21319
|
-
}
|
|
21320
21897
|
const res = adapter.processTextContent(txt, "");
|
|
21321
21898
|
log(`[Streaming] After adapter: "${res.cleanedText.substring(0, 30).replace(/\n/g, "\\n")}" (${res.cleanedText.length} chars, transformed=${res.wasTransformed})`);
|
|
21322
21899
|
if (txt.length > 0 && res.cleanedText.length === 0) {
|
|
21323
21900
|
log(`[Streaming] Text filtered out by adapter: "${txt.substring(0, 50)}"`);
|
|
21324
21901
|
}
|
|
21325
21902
|
if (res.cleanedText) {
|
|
21326
|
-
|
|
21327
|
-
const hasStructuredToolPattern = hasExtractableFunctionTag(state.accumulatedText) || /\{\s*"(?:name|tool)"\s*:\s*"(?:Task|Read|Write|Edit|Bash|Grep|Glob)"/i.test(state.accumulatedText) || /<tool_call>/.test(state.accumulatedText);
|
|
21328
|
-
const shouldHoldBack = hasStructuredToolPattern && state.accumulatedText.length < 1000;
|
|
21329
|
-
if (shouldHoldBack) {
|
|
21330
|
-
log(`[Streaming] Text held back (structured tool pattern): ${state.accumulatedText.length} chars accumulated`);
|
|
21331
|
-
}
|
|
21332
|
-
if (!shouldHoldBack) {
|
|
21333
|
-
if (!state.textStarted) {
|
|
21334
|
-
state.textIdx = state.curIdx++;
|
|
21335
|
-
send("content_block_start", {
|
|
21336
|
-
type: "content_block_start",
|
|
21337
|
-
index: state.textIdx,
|
|
21338
|
-
content_block: { type: "text", text: "" }
|
|
21339
|
-
});
|
|
21340
|
-
state.textStarted = true;
|
|
21341
|
-
log(`[Streaming] Started text block at index ${state.textIdx}`);
|
|
21342
|
-
}
|
|
21343
|
-
send("content_block_delta", {
|
|
21344
|
-
type: "content_block_delta",
|
|
21345
|
-
index: state.textIdx,
|
|
21346
|
-
delta: { type: "text_delta", text: res.cleanedText }
|
|
21347
|
-
});
|
|
21348
|
-
}
|
|
21903
|
+
emitSplitContent(thinkSplitter.push(res.cleanedText));
|
|
21349
21904
|
}
|
|
21350
21905
|
}
|
|
21351
21906
|
if (delta.tool_calls) {
|
|
@@ -21354,57 +21909,62 @@ data: ${JSON.stringify(d)}
|
|
|
21354
21909
|
const idx = tc.index;
|
|
21355
21910
|
let t = state.tools.get(idx);
|
|
21356
21911
|
if (tc.function?.name) {
|
|
21912
|
+
const accumulatedName = (state.pendingToolName.get(idx) ?? "") + tc.function.name;
|
|
21913
|
+
state.pendingToolName.set(idx, accumulatedName);
|
|
21914
|
+
const restoredName = toolNameMap?.get(accumulatedName) || accumulatedName;
|
|
21357
21915
|
if (!t) {
|
|
21358
|
-
if (state.reasoningStarted) {
|
|
21359
|
-
send("content_block_stop", {
|
|
21360
|
-
type: "content_block_stop",
|
|
21361
|
-
index: state.reasoningIdx
|
|
21362
|
-
});
|
|
21363
|
-
state.reasoningStarted = false;
|
|
21364
|
-
}
|
|
21365
|
-
if (state.textStarted) {
|
|
21366
|
-
send("content_block_stop", {
|
|
21367
|
-
type: "content_block_stop",
|
|
21368
|
-
index: state.textIdx
|
|
21369
|
-
});
|
|
21370
|
-
state.textStarted = false;
|
|
21371
|
-
}
|
|
21372
|
-
const rawName = tc.function.name;
|
|
21373
|
-
const restoredName = toolNameMap?.get(rawName) || rawName;
|
|
21374
21916
|
t = {
|
|
21375
21917
|
id: tc.id || `tool_${Date.now()}_${idx}`,
|
|
21376
21918
|
name: restoredName,
|
|
21377
|
-
blockIndex:
|
|
21919
|
+
blockIndex: writer.reserve(),
|
|
21378
21920
|
started: false,
|
|
21379
21921
|
closed: false,
|
|
21380
|
-
arguments: "",
|
|
21922
|
+
arguments: state.pendingToolArgs.get(idx) ?? "",
|
|
21923
|
+
ref: null,
|
|
21381
21924
|
buffered: !!toolSchemas && toolSchemas.length > 0 || behavior?.shouldBufferTool?.(restoredName) === true
|
|
21382
21925
|
};
|
|
21926
|
+
if (t.arguments) {
|
|
21927
|
+
log(`[Streaming] tool ${t.name} (index ${idx}): seeded ${t.arguments.length} argument chars that arrived before function.name`);
|
|
21928
|
+
}
|
|
21929
|
+
state.pendingToolArgs.delete(idx);
|
|
21383
21930
|
state.tools.set(idx, t);
|
|
21384
21931
|
if (isWebSearchToolCall(restoredName)) {
|
|
21385
21932
|
warnWebSearchUnsupported(restoredName, target);
|
|
21386
21933
|
}
|
|
21934
|
+
} else if (t.name !== restoredName) {
|
|
21935
|
+
if (t.started) {
|
|
21936
|
+
log(`[Streaming] error: tool block ${t.blockIndex} was started as "${t.name}" but the full name is "${restoredName}" \u2014 the client sees the wrong name`);
|
|
21937
|
+
} else {
|
|
21938
|
+
t.name = restoredName;
|
|
21939
|
+
t.buffered = !!toolSchemas && toolSchemas.length > 0 || behavior?.shouldBufferTool?.(restoredName) === true;
|
|
21940
|
+
if (isWebSearchToolCall(restoredName)) {
|
|
21941
|
+
warnWebSearchUnsupported(restoredName, target);
|
|
21942
|
+
}
|
|
21943
|
+
}
|
|
21387
21944
|
}
|
|
21388
21945
|
if (!t.started && !t.buffered) {
|
|
21389
|
-
|
|
21390
|
-
|
|
21391
|
-
|
|
21392
|
-
|
|
21946
|
+
t.ref = writer.openTool({
|
|
21947
|
+
id: t.id,
|
|
21948
|
+
name: t.name,
|
|
21949
|
+
index: t.blockIndex
|
|
21393
21950
|
});
|
|
21394
21951
|
t.started = true;
|
|
21952
|
+
if (t.arguments)
|
|
21953
|
+
writer.append(t.ref, t.arguments);
|
|
21395
21954
|
}
|
|
21396
21955
|
}
|
|
21956
|
+
if (tc.function?.arguments && !t) {
|
|
21957
|
+
state.pendingToolArgs.set(idx, (state.pendingToolArgs.get(idx) ?? "") + tc.function.arguments);
|
|
21958
|
+
}
|
|
21397
21959
|
if (tc.function?.arguments && t) {
|
|
21398
21960
|
t.arguments += tc.function.arguments;
|
|
21399
21961
|
if (!t.buffered) {
|
|
21400
|
-
|
|
21401
|
-
|
|
21402
|
-
|
|
21403
|
-
|
|
21404
|
-
|
|
21405
|
-
|
|
21406
|
-
}
|
|
21407
|
-
});
|
|
21962
|
+
if (!t.ref || !writer.append(t.ref, tc.function.arguments)) {
|
|
21963
|
+
log(`[Streaming] tool ${t.name} (index ${idx}) lost its open block mid-arguments \u2014 buffering the rest`);
|
|
21964
|
+
t.buffered = true;
|
|
21965
|
+
t.started = false;
|
|
21966
|
+
t.ref = null;
|
|
21967
|
+
}
|
|
21408
21968
|
}
|
|
21409
21969
|
}
|
|
21410
21970
|
}
|
|
@@ -21420,110 +21980,74 @@ data: ${JSON.stringify(d)}
|
|
|
21420
21980
|
const repairedJson = repairArgs(t.name, JSON.stringify(validation.repairedArgs));
|
|
21421
21981
|
log(`[Streaming] Sending repaired tool call: ${t.name} with args: ${repairedJson}`);
|
|
21422
21982
|
if (t.buffered && !t.started) {
|
|
21423
|
-
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
content_block: { type: "tool_use", id: t.id, name: t.name }
|
|
21427
|
-
});
|
|
21428
|
-
send("content_block_delta", {
|
|
21429
|
-
type: "content_block_delta",
|
|
21430
|
-
index: t.blockIndex,
|
|
21431
|
-
delta: { type: "input_json_delta", partial_json: repairedJson }
|
|
21432
|
-
});
|
|
21433
|
-
send("content_block_stop", {
|
|
21434
|
-
type: "content_block_stop",
|
|
21983
|
+
t.ref = writer.openTool({
|
|
21984
|
+
id: t.id,
|
|
21985
|
+
name: t.name,
|
|
21435
21986
|
index: t.blockIndex
|
|
21436
21987
|
});
|
|
21988
|
+
writer.append(t.ref, repairedJson);
|
|
21989
|
+
writer.close(t.ref);
|
|
21437
21990
|
t.started = true;
|
|
21438
21991
|
t.closed = true;
|
|
21439
21992
|
continue;
|
|
21440
21993
|
}
|
|
21441
21994
|
if (t.started) {
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
});
|
|
21446
|
-
const repairedIdx = state.curIdx++;
|
|
21995
|
+
if (t.ref)
|
|
21996
|
+
writer.close(t.ref);
|
|
21997
|
+
const repairedIdx = writer.reserve();
|
|
21447
21998
|
const repairedId = `tool_repaired_${Date.now()}_${repairedIdx}`;
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
content_block: { type: "tool_use", id: repairedId, name: t.name }
|
|
21452
|
-
});
|
|
21453
|
-
send("content_block_delta", {
|
|
21454
|
-
type: "content_block_delta",
|
|
21455
|
-
index: repairedIdx,
|
|
21456
|
-
delta: { type: "input_json_delta", partial_json: repairedJson }
|
|
21457
|
-
});
|
|
21458
|
-
send("content_block_stop", {
|
|
21459
|
-
type: "content_block_stop",
|
|
21999
|
+
const repairedRef = writer.openTool({
|
|
22000
|
+
id: repairedId,
|
|
22001
|
+
name: t.name,
|
|
21460
22002
|
index: repairedIdx
|
|
21461
22003
|
});
|
|
22004
|
+
writer.append(repairedRef, repairedJson);
|
|
22005
|
+
writer.close(repairedRef);
|
|
22006
|
+
t.ref = repairedRef;
|
|
21462
22007
|
t.closed = true;
|
|
21463
22008
|
continue;
|
|
21464
22009
|
}
|
|
21465
22010
|
}
|
|
21466
22011
|
if (!validation.valid) {
|
|
21467
22012
|
log(`[Streaming] Tool call ${t.name} validation failed: ${validation.missingParams.join(", ")}`);
|
|
21468
|
-
const errorIdx = t.buffered ? t.blockIndex :
|
|
22013
|
+
const errorIdx = t.buffered ? t.blockIndex : undefined;
|
|
21469
22014
|
const errorMsg = `
|
|
21470
22015
|
|
|
21471
22016
|
\u26A0\uFE0F Tool call "${t.name}" failed: missing required parameters: ${validation.missingParams.join(", ")}. Local models sometimes generate incomplete tool calls. Please try again or use a model with better tool support.`;
|
|
21472
|
-
|
|
21473
|
-
|
|
21474
|
-
|
|
21475
|
-
|
|
21476
|
-
|
|
21477
|
-
send("content_block_delta", {
|
|
21478
|
-
type: "content_block_delta",
|
|
21479
|
-
index: errorIdx,
|
|
21480
|
-
delta: { type: "text_delta", text: errorMsg }
|
|
21481
|
-
});
|
|
21482
|
-
send("content_block_stop", {
|
|
21483
|
-
type: "content_block_stop",
|
|
21484
|
-
index: errorIdx
|
|
21485
|
-
});
|
|
21486
|
-
if (t.started && !t.buffered) {
|
|
21487
|
-
send("content_block_stop", {
|
|
21488
|
-
type: "content_block_stop",
|
|
21489
|
-
index: t.blockIndex
|
|
21490
|
-
});
|
|
22017
|
+
const errorRef = writer.openText({ index: errorIdx });
|
|
22018
|
+
writer.append(errorRef, errorMsg);
|
|
22019
|
+
writer.close(errorRef);
|
|
22020
|
+
if (t.started && !t.buffered && t.ref) {
|
|
22021
|
+
writer.close(t.ref);
|
|
21491
22022
|
}
|
|
21492
22023
|
t.closed = true;
|
|
21493
22024
|
continue;
|
|
21494
22025
|
}
|
|
21495
22026
|
if (t.buffered && !t.started) {
|
|
21496
22027
|
const argsJson = repairArgs(t.name, JSON.stringify(validation.parsedArgs));
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
content_block: { type: "tool_use", id: t.id, name: t.name }
|
|
21501
|
-
});
|
|
21502
|
-
send("content_block_delta", {
|
|
21503
|
-
type: "content_block_delta",
|
|
21504
|
-
index: t.blockIndex,
|
|
21505
|
-
delta: { type: "input_json_delta", partial_json: argsJson }
|
|
21506
|
-
});
|
|
21507
|
-
send("content_block_stop", {
|
|
21508
|
-
type: "content_block_stop",
|
|
22028
|
+
t.ref = writer.openTool({
|
|
22029
|
+
id: t.id,
|
|
22030
|
+
name: t.name,
|
|
21509
22031
|
index: t.blockIndex
|
|
21510
22032
|
});
|
|
22033
|
+
writer.append(t.ref, argsJson);
|
|
22034
|
+
writer.close(t.ref);
|
|
21511
22035
|
t.started = true;
|
|
21512
22036
|
t.closed = true;
|
|
21513
22037
|
continue;
|
|
21514
22038
|
}
|
|
21515
22039
|
}
|
|
21516
22040
|
if (t.started && !t.closed) {
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
index: t.blockIndex
|
|
21520
|
-
});
|
|
22041
|
+
if (t.ref)
|
|
22042
|
+
writer.close(t.ref);
|
|
21521
22043
|
t.closed = true;
|
|
21522
22044
|
}
|
|
21523
22045
|
}
|
|
21524
22046
|
}
|
|
21525
22047
|
}
|
|
21526
|
-
} catch (e) {
|
|
22048
|
+
} catch (e) {
|
|
22049
|
+
log(`[Streaming] Chunk processing error (chunk dropped): ${e} \u2014 payload starts: ${dataStr.slice(0, 120)}`);
|
|
22050
|
+
}
|
|
21527
22051
|
}
|
|
21528
22052
|
}
|
|
21529
22053
|
await finalize("unexpected");
|
|
@@ -21549,10 +22073,13 @@ var init_openai_sse = __esm(() => {
|
|
|
21549
22073
|
init_logger();
|
|
21550
22074
|
init_tool_call_recovery();
|
|
21551
22075
|
init_web_search_detector();
|
|
22076
|
+
init_block_writer();
|
|
22077
|
+
init_think_tag_splitter();
|
|
21552
22078
|
});
|
|
21553
22079
|
|
|
21554
22080
|
// src/handlers/shared/openai-compat.ts
|
|
21555
22081
|
var init_openai_compat = __esm(() => {
|
|
22082
|
+
init_openai_messages();
|
|
21556
22083
|
init_openai_tools();
|
|
21557
22084
|
init_openai_sse();
|
|
21558
22085
|
});
|
|
@@ -21560,6 +22087,7 @@ var init_openai_compat = __esm(() => {
|
|
|
21560
22087
|
// src/adapters/gemini-api-format.ts
|
|
21561
22088
|
var GeminiAPIFormat;
|
|
21562
22089
|
var init_gemini_api_format = __esm(() => {
|
|
22090
|
+
init_openai_tools();
|
|
21563
22091
|
init_gemini_schema();
|
|
21564
22092
|
init_openai_compat();
|
|
21565
22093
|
init_logger();
|
|
@@ -21704,6 +22232,11 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
|
|
|
21704
22232
|
}
|
|
21705
22233
|
if (tools && tools.length > 0) {
|
|
21706
22234
|
payload.tools = tools;
|
|
22235
|
+
const toolConfig = mapToolChoiceToGemini(claudeRequest.tool_choice);
|
|
22236
|
+
if (toolConfig) {
|
|
22237
|
+
payload.toolConfig = toolConfig;
|
|
22238
|
+
log(`[GeminiAPIFormat] toolConfig.mode -> ${toolConfig.functionCallingConfig.mode} for ${this.modelId}`);
|
|
22239
|
+
}
|
|
21707
22240
|
}
|
|
21708
22241
|
const effort = this.resolveEffortLevel(claudeRequest);
|
|
21709
22242
|
if (effort) {
|
|
@@ -21825,6 +22358,7 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
|
|
|
21825
22358
|
// src/adapters/litellm-api-format.ts
|
|
21826
22359
|
var INLINE_IMAGE_MODEL_PATTERNS, LiteLLMAPIFormat;
|
|
21827
22360
|
var init_litellm_api_format = __esm(() => {
|
|
22361
|
+
init_openai_tools();
|
|
21828
22362
|
init_logger();
|
|
21829
22363
|
init_base_api_format();
|
|
21830
22364
|
INLINE_IMAGE_MODEL_PATTERNS = ["minimax"];
|
|
@@ -21900,14 +22434,11 @@ var init_litellm_api_format = __esm(() => {
|
|
|
21900
22434
|
if (tools.length > 0) {
|
|
21901
22435
|
payload.tools = tools;
|
|
21902
22436
|
}
|
|
21903
|
-
|
|
21904
|
-
|
|
21905
|
-
|
|
21906
|
-
payload.tool_choice = { type: "function", function: { name } };
|
|
21907
|
-
} else if (type === "auto" || type === "none") {
|
|
21908
|
-
payload.tool_choice = type;
|
|
21909
|
-
}
|
|
22437
|
+
const toolChoice = mapToolChoiceToOpenAI(claudeRequest.tool_choice);
|
|
22438
|
+
if (toolChoice !== undefined) {
|
|
22439
|
+
payload.tool_choice = toolChoice;
|
|
21910
22440
|
}
|
|
22441
|
+
this.applyOpenAISamplingParams(payload, claudeRequest);
|
|
21911
22442
|
return payload;
|
|
21912
22443
|
}
|
|
21913
22444
|
checkVisionSupport() {
|
|
@@ -22010,6 +22541,7 @@ var init_ollama_api_format = __esm(() => {
|
|
|
22010
22541
|
// src/adapters/openai-api-format.ts
|
|
22011
22542
|
var OpenAIAPIFormat;
|
|
22012
22543
|
var init_openai_api_format = __esm(() => {
|
|
22544
|
+
init_openai_tools();
|
|
22013
22545
|
init_logger();
|
|
22014
22546
|
init_base_api_format();
|
|
22015
22547
|
init_model_catalog();
|
|
@@ -22027,13 +22559,6 @@ var init_openai_api_format = __esm(() => {
|
|
|
22027
22559
|
getMaxToolCount() {
|
|
22028
22560
|
return 128;
|
|
22029
22561
|
}
|
|
22030
|
-
prepareRequestCommon(request, _originalRequest) {
|
|
22031
|
-
this.truncateToolNames(request);
|
|
22032
|
-
if (request.messages) {
|
|
22033
|
-
this.truncateToolNamesInMessages(request.messages);
|
|
22034
|
-
}
|
|
22035
|
-
return request;
|
|
22036
|
-
}
|
|
22037
22562
|
applyNativeReasoning(request, originalRequest) {
|
|
22038
22563
|
if (this.supportsReasoningEffort() && request.reasoning_effort === undefined) {
|
|
22039
22564
|
const effort = this.resolveReasoningEffort(originalRequest);
|
|
@@ -22187,13 +22712,9 @@ var init_openai_api_format = __esm(() => {
|
|
|
22187
22712
|
if (tools.length > 0) {
|
|
22188
22713
|
payload.tools = tools;
|
|
22189
22714
|
}
|
|
22190
|
-
|
|
22191
|
-
|
|
22192
|
-
|
|
22193
|
-
payload.tool_choice = { type: "function", function: { name } };
|
|
22194
|
-
} else if (type === "auto" || type === "none") {
|
|
22195
|
-
payload.tool_choice = type;
|
|
22196
|
-
}
|
|
22715
|
+
const toolChoice = mapToolChoiceToOpenAI(claudeRequest.tool_choice);
|
|
22716
|
+
if (toolChoice !== undefined) {
|
|
22717
|
+
payload.tool_choice = toolChoice;
|
|
22197
22718
|
}
|
|
22198
22719
|
if (this.supportsReasoningEffort()) {
|
|
22199
22720
|
const effort = this.resolveReasoningEffort(claudeRequest);
|
|
@@ -22202,6 +22723,7 @@ var init_openai_api_format = __esm(() => {
|
|
|
22202
22723
|
log(`[OpenAIAPIFormat] reasoning_effort -> ${effort} for ${this.modelId}`);
|
|
22203
22724
|
}
|
|
22204
22725
|
}
|
|
22726
|
+
this.applyOpenAISamplingParams(payload, claudeRequest);
|
|
22205
22727
|
return payload;
|
|
22206
22728
|
}
|
|
22207
22729
|
};
|
|
@@ -22688,30 +23210,30 @@ var init_grok_model_dialect = __esm(() => {
|
|
|
22688
23210
|
return value;
|
|
22689
23211
|
}
|
|
22690
23212
|
recoverFromRejection(payload, errorText) {
|
|
22691
|
-
if (
|
|
22692
|
-
|
|
22693
|
-
|
|
22694
|
-
|
|
22695
|
-
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
|
|
22704
|
-
|
|
22705
|
-
|
|
22706
|
-
|
|
22707
|
-
|
|
22708
|
-
|
|
22709
|
-
}
|
|
23213
|
+
if (payload?.reasoning_effort !== undefined) {
|
|
23214
|
+
if (isReasoningEffortRejection(errorText)) {
|
|
23215
|
+
rememberReasoningEffortRejected(this.modelId);
|
|
23216
|
+
const next = { ...payload };
|
|
23217
|
+
delete next.reasoning_effort;
|
|
23218
|
+
return { payload: next, note: `dropped reasoning_effort for ${this.modelId}` };
|
|
23219
|
+
}
|
|
23220
|
+
const rejected = rejectedReasoningEffortValue(errorText);
|
|
23221
|
+
if (rejected) {
|
|
23222
|
+
rememberReasoningEffortValueRejected(this.modelId, rejected);
|
|
23223
|
+
const fallback = fallbackReasoningEffortValue(rejected);
|
|
23224
|
+
const next = { ...payload };
|
|
23225
|
+
if (fallback) {
|
|
23226
|
+
next.reasoning_effort = fallback;
|
|
23227
|
+
return {
|
|
23228
|
+
payload: next,
|
|
23229
|
+
note: `reasoning_effort "${rejected}" -> "${fallback}" for ${this.modelId}`
|
|
23230
|
+
};
|
|
23231
|
+
}
|
|
23232
|
+
delete next.reasoning_effort;
|
|
23233
|
+
return { payload: next, note: `dropped unsupported reasoning_effort for ${this.modelId}` };
|
|
22710
23234
|
}
|
|
22711
|
-
delete next.reasoning_effort;
|
|
22712
|
-
return { payload: next, note: `dropped unsupported reasoning_effort for ${this.modelId}` };
|
|
22713
23235
|
}
|
|
22714
|
-
return
|
|
23236
|
+
return super.recoverFromRejection(payload, errorText);
|
|
22715
23237
|
}
|
|
22716
23238
|
parseXmlParameters(xmlContent) {
|
|
22717
23239
|
const params = {};
|
|
@@ -22738,6 +23260,7 @@ var init_grok_model_dialect = __esm(() => {
|
|
|
22738
23260
|
return lookupModel(this.modelId)?.contextWindow ?? 0;
|
|
22739
23261
|
}
|
|
22740
23262
|
reset() {
|
|
23263
|
+
super.reset();
|
|
22741
23264
|
this.xmlBuffer = "";
|
|
22742
23265
|
}
|
|
22743
23266
|
};
|
|
@@ -22881,16 +23404,6 @@ var init_xiaomi_model_dialect = __esm(() => {
|
|
|
22881
23404
|
wasTransformed: false
|
|
22882
23405
|
};
|
|
22883
23406
|
}
|
|
22884
|
-
getToolNameLimit() {
|
|
22885
|
-
return 64;
|
|
22886
|
-
}
|
|
22887
|
-
prepareRequestCommon(request, _originalRequest) {
|
|
22888
|
-
this.truncateToolNames(request);
|
|
22889
|
-
if (request.messages) {
|
|
22890
|
-
this.truncateToolNamesInMessages(request.messages);
|
|
22891
|
-
}
|
|
22892
|
-
return request;
|
|
22893
|
-
}
|
|
22894
23407
|
applyNativeReasoning(request, originalRequest) {
|
|
22895
23408
|
if (originalRequest.thinking) {
|
|
22896
23409
|
log("[XiaomiModelDialect] Stripping thinking object (not supported by Xiaomi API)");
|
|
@@ -31672,6 +32185,31 @@ var init_stats = __esm(() => {
|
|
|
31672
32185
|
});
|
|
31673
32186
|
});
|
|
31674
32187
|
|
|
32188
|
+
// src/handlers/shared/request-shape.ts
|
|
32189
|
+
function isRequestShapeError(errorBody) {
|
|
32190
|
+
if (!errorBody)
|
|
32191
|
+
return false;
|
|
32192
|
+
const lower = errorBody.toLowerCase();
|
|
32193
|
+
return lower.includes("unknown_parameter") || lower.includes("unsupported_parameter") || lower.includes("invalid_parameter") || lower.includes("unknown parameter:") || lower.includes("unsupported parameter:") || lower.includes("invalid parameter:");
|
|
32194
|
+
}
|
|
32195
|
+
function isContextOverflowError(status, errorBody) {
|
|
32196
|
+
if (!errorBody)
|
|
32197
|
+
return false;
|
|
32198
|
+
if (isRequestShapeError(errorBody))
|
|
32199
|
+
return false;
|
|
32200
|
+
const lower = errorBody.toLowerCase();
|
|
32201
|
+
if (lower.includes("context_length_exceeded") || lower.includes("string_above_max_length") || lower.includes("request_too_large") || lower.includes("context_window_exceeded") || lower.includes("prompt_too_long")) {
|
|
32202
|
+
return true;
|
|
32203
|
+
}
|
|
32204
|
+
if (lower.includes("maximum context length is") || lower.includes("reduce the length of the messages") || lower.includes("input is too long") || lower.includes(CONTEXT_OVERFLOW_PHRASE)) {
|
|
32205
|
+
return true;
|
|
32206
|
+
}
|
|
32207
|
+
if (status === 413 && (lower.includes("token") || lower.includes("context")))
|
|
32208
|
+
return true;
|
|
32209
|
+
return false;
|
|
32210
|
+
}
|
|
32211
|
+
var CONTEXT_OVERFLOW_PHRASE = "prompt is too long";
|
|
32212
|
+
|
|
31675
32213
|
// src/handlers/shared/anthropic-error.ts
|
|
31676
32214
|
function statusToErrorType(status) {
|
|
31677
32215
|
switch (status) {
|
|
@@ -31750,6 +32288,8 @@ function isTerminalError(status, bodyText, terminal429) {
|
|
|
31750
32288
|
return true;
|
|
31751
32289
|
if (status === 429 && terminal429)
|
|
31752
32290
|
return true;
|
|
32291
|
+
if (isContextOverflowError(status, bodyText))
|
|
32292
|
+
return true;
|
|
31753
32293
|
const lower = (bodyText || "").toLowerCase();
|
|
31754
32294
|
if (lower.includes("insufficient balance") || lower.includes("insufficient_balance") || lower.includes("insufficient_quota") || lower.includes("insufficient quota") || lower.includes("billing_not_active") || lower.includes("billing not active") || lower.includes("out of credits") || lower.includes("no credits remaining") || lower.includes("exceeded your current quota") || lower.includes("quota_exceeded")) {
|
|
31755
32295
|
return true;
|
|
@@ -31763,11 +32303,13 @@ function isTerminalError(status, bodyText, terminal429) {
|
|
|
31763
32303
|
return false;
|
|
31764
32304
|
}
|
|
31765
32305
|
function buildSurfacedErrorMessage(opts) {
|
|
31766
|
-
const { providerDisplayName, status, hint, providerMessage } = opts;
|
|
32306
|
+
const { providerDisplayName, status, hint, providerMessage, leadPhrase } = opts;
|
|
31767
32307
|
const head = `${providerDisplayName} error (HTTP ${status})`;
|
|
31768
32308
|
const parts = [head];
|
|
31769
32309
|
if (hint)
|
|
31770
32310
|
parts[0] = `${head}: ${hint}`;
|
|
32311
|
+
if (leadPhrase && !parts[0].startsWith(leadPhrase))
|
|
32312
|
+
parts[0] = `${leadPhrase} \u2014 ${parts[0]}`;
|
|
31771
32313
|
const detail = (providerMessage || "").trim();
|
|
31772
32314
|
if (detail && !parts[0].includes(detail)) {
|
|
31773
32315
|
const trimmed = detail.length > 600 ? `${detail.slice(0, 600)}\u2026` : detail;
|
|
@@ -32177,14 +32719,6 @@ var init_model_unsupported = __esm(() => {
|
|
|
32177
32719
|
];
|
|
32178
32720
|
});
|
|
32179
32721
|
|
|
32180
|
-
// src/handlers/shared/request-shape.ts
|
|
32181
|
-
function isRequestShapeError(errorBody) {
|
|
32182
|
-
if (!errorBody)
|
|
32183
|
-
return false;
|
|
32184
|
-
const lower = errorBody.toLowerCase();
|
|
32185
|
-
return lower.includes("unknown_parameter") || lower.includes("unsupported_parameter") || lower.includes("invalid_parameter") || lower.includes("unknown parameter:") || lower.includes("unsupported parameter:") || lower.includes("invalid parameter:");
|
|
32186
|
-
}
|
|
32187
|
-
|
|
32188
32722
|
// src/handlers/shared/stream-head-sniffer.ts
|
|
32189
32723
|
function isRetryableStreamError(code, type, message) {
|
|
32190
32724
|
if (RETRYABLE_ERROR_CODES.has(code))
|
|
@@ -33938,6 +34472,17 @@ function stripProviderPrefix(name) {
|
|
|
33938
34472
|
const at = name.indexOf("@");
|
|
33939
34473
|
return at === -1 ? name : name.slice(at + 1);
|
|
33940
34474
|
}
|
|
34475
|
+
function computeCacheReadDiscount(pricing, billedInputTokens, detail) {
|
|
34476
|
+
const cacheReadTokens = detail?.cacheReadTokens ?? 0;
|
|
34477
|
+
if (cacheReadTokens <= 0 || billedInputTokens <= 0)
|
|
34478
|
+
return 0;
|
|
34479
|
+
const rate = pricing.cacheReadCostPer1M ?? pricing.inputCostPer1M;
|
|
34480
|
+
const perMillionSaved = pricing.inputCostPer1M - rate;
|
|
34481
|
+
if (!(perMillionSaved > 0))
|
|
34482
|
+
return 0;
|
|
34483
|
+
const discountedTokens = Math.min(cacheReadTokens, billedInputTokens);
|
|
34484
|
+
return discountedTokens / 1e6 * perMillionSaved;
|
|
34485
|
+
}
|
|
33941
34486
|
|
|
33942
34487
|
class TokenTracker {
|
|
33943
34488
|
port;
|
|
@@ -33952,6 +34497,7 @@ class TokenTracker {
|
|
|
33952
34497
|
toolCallsByName = new Map;
|
|
33953
34498
|
startedAt = Date.now();
|
|
33954
34499
|
sessionBilledInputTokens = 0;
|
|
34500
|
+
sessionCacheReadTokens = 0;
|
|
33955
34501
|
constructor(port, config) {
|
|
33956
34502
|
this.port = port;
|
|
33957
34503
|
this.config = config;
|
|
@@ -33987,27 +34533,32 @@ class TokenTracker {
|
|
|
33987
34533
|
rewrite() {
|
|
33988
34534
|
this.writeFile(this.getLastInputTokens(), this.sessionOutputTokens);
|
|
33989
34535
|
}
|
|
33990
|
-
update(inputTokens, outputTokens) {
|
|
34536
|
+
update(inputTokens, outputTokens, detail) {
|
|
33991
34537
|
this.sessionInputTokens = inputTokens;
|
|
33992
34538
|
this.lastInputTokens = inputTokens;
|
|
33993
34539
|
this.sessionOutputTokens += outputTokens;
|
|
33994
34540
|
this.sessionBilledInputTokens += inputTokens;
|
|
34541
|
+
this.sessionCacheReadTokens += detail?.cacheReadTokens ?? 0;
|
|
33995
34542
|
const pricing = this.getPricing();
|
|
33996
|
-
const cost = inputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M;
|
|
34543
|
+
const cost = inputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M - this.cacheReadDiscount(pricing, inputTokens, detail);
|
|
33997
34544
|
this.sessionTotalCost += cost;
|
|
33998
34545
|
this.writeFile(inputTokens, this.sessionOutputTokens, pricing.isEstimate);
|
|
33999
34546
|
}
|
|
34000
|
-
accumulateBoth(inputTokens, outputTokens) {
|
|
34547
|
+
accumulateBoth(inputTokens, outputTokens, detail) {
|
|
34001
34548
|
this.sessionInputTokens += inputTokens;
|
|
34002
34549
|
this.lastInputTokens = this.sessionInputTokens;
|
|
34003
34550
|
this.sessionOutputTokens += outputTokens;
|
|
34551
|
+
this.sessionCacheReadTokens += detail?.cacheReadTokens ?? 0;
|
|
34004
34552
|
const pricing = this.getPricing();
|
|
34005
|
-
const cost = this.sessionInputTokens / 1e6 * pricing.inputCostPer1M + this.sessionOutputTokens / 1e6 * pricing.outputCostPer1M
|
|
34553
|
+
const cost = this.sessionInputTokens / 1e6 * pricing.inputCostPer1M + this.sessionOutputTokens / 1e6 * pricing.outputCostPer1M - this.cacheReadDiscount(pricing, this.sessionInputTokens, {
|
|
34554
|
+
cacheReadTokens: this.sessionCacheReadTokens,
|
|
34555
|
+
cacheCreationTokens: 0
|
|
34556
|
+
});
|
|
34006
34557
|
this.sessionTotalCost = cost;
|
|
34007
34558
|
this.sessionBilledInputTokens = this.sessionInputTokens;
|
|
34008
34559
|
this.writeFile(this.sessionInputTokens, this.sessionOutputTokens, pricing.isEstimate);
|
|
34009
34560
|
}
|
|
34010
|
-
updateWithDelta(inputTokens, outputTokens) {
|
|
34561
|
+
updateWithDelta(inputTokens, outputTokens, detail) {
|
|
34011
34562
|
let incrementalInputTokens;
|
|
34012
34563
|
this.lastInputTokens = inputTokens;
|
|
34013
34564
|
if (inputTokens >= this.sessionInputTokens) {
|
|
@@ -34022,17 +34573,19 @@ class TokenTracker {
|
|
|
34022
34573
|
log(`[TokenTracker] Ambiguous token decrease (${inputTokens} vs ${this.sessionInputTokens}), charging full input`);
|
|
34023
34574
|
}
|
|
34024
34575
|
this.sessionOutputTokens += outputTokens;
|
|
34576
|
+
this.sessionCacheReadTokens += detail?.cacheReadTokens ?? 0;
|
|
34025
34577
|
const pricing = this.getPricing();
|
|
34026
34578
|
this.sessionBilledInputTokens += incrementalInputTokens;
|
|
34027
|
-
const cost = incrementalInputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M;
|
|
34579
|
+
const cost = incrementalInputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M - this.cacheReadDiscount(pricing, incrementalInputTokens, detail);
|
|
34028
34580
|
this.sessionTotalCost += cost;
|
|
34029
34581
|
this.writeFile(inputTokens, this.sessionOutputTokens, pricing.isEstimate);
|
|
34030
34582
|
}
|
|
34031
|
-
updateWithActualCost(inputTokens, outputTokens, actualCost) {
|
|
34583
|
+
updateWithActualCost(inputTokens, outputTokens, actualCost, detail) {
|
|
34032
34584
|
this.sessionInputTokens = inputTokens;
|
|
34033
34585
|
this.lastInputTokens = inputTokens;
|
|
34034
34586
|
this.sessionOutputTokens += outputTokens;
|
|
34035
34587
|
this.sessionBilledInputTokens += inputTokens;
|
|
34588
|
+
this.sessionCacheReadTokens += detail?.cacheReadTokens ?? 0;
|
|
34036
34589
|
if (typeof actualCost === "number" && actualCost > 0) {
|
|
34037
34590
|
this.sessionTotalCost += actualCost;
|
|
34038
34591
|
log(`[TokenTracker] Actual cost from API: $${actualCost.toFixed(6)}`);
|
|
@@ -34040,11 +34593,11 @@ class TokenTracker {
|
|
|
34040
34593
|
const pricing = this.getPricing();
|
|
34041
34594
|
const inputCost = inputTokens / 1e6 * pricing.inputCostPer1M;
|
|
34042
34595
|
const outputCost = outputTokens / 1e6 * pricing.outputCostPer1M;
|
|
34043
|
-
this.sessionTotalCost += inputCost + outputCost;
|
|
34596
|
+
this.sessionTotalCost += inputCost + outputCost - this.cacheReadDiscount(pricing, inputTokens, detail);
|
|
34044
34597
|
}
|
|
34045
34598
|
this.writeFile(inputTokens, this.sessionOutputTokens);
|
|
34046
34599
|
}
|
|
34047
|
-
updateLocal(inputTokens, outputTokens) {
|
|
34600
|
+
updateLocal(inputTokens, outputTokens, _detail) {
|
|
34048
34601
|
if (inputTokens > 0) {
|
|
34049
34602
|
this.sessionInputTokens = inputTokens;
|
|
34050
34603
|
this.lastInputTokens = inputTokens;
|
|
@@ -34074,6 +34627,9 @@ class TokenTracker {
|
|
|
34074
34627
|
getPricing() {
|
|
34075
34628
|
return getModelPricing(this.config.providerName, this.config.modelName);
|
|
34076
34629
|
}
|
|
34630
|
+
cacheReadDiscount(pricing, billedInputTokens, detail) {
|
|
34631
|
+
return computeCacheReadDiscount(pricing, billedInputTokens, detail);
|
|
34632
|
+
}
|
|
34077
34633
|
getDisplayName() {
|
|
34078
34634
|
if (this.config.providerDisplayName)
|
|
34079
34635
|
return this.config.providerDisplayName;
|
|
@@ -34242,6 +34798,9 @@ class ComposedHandler {
|
|
|
34242
34798
|
if (resolvedModelAdapter.getName() !== "DefaultAPIFormat") {
|
|
34243
34799
|
this.modelAdapter = resolvedModelAdapter;
|
|
34244
34800
|
}
|
|
34801
|
+
const responseWire = this.resolveStreamFormat();
|
|
34802
|
+
this.resolvedDialect.setResponseWireFormat(responseWire);
|
|
34803
|
+
this.explicitAdapter?.setResponseWireFormat(responseWire);
|
|
34245
34804
|
this.middlewareManager = new MiddlewareManager;
|
|
34246
34805
|
if (this.bareModelName.includes("gemini") || this.bareModelName.includes("google/")) {
|
|
34247
34806
|
this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
|
|
@@ -34508,9 +35067,15 @@ class ComposedHandler {
|
|
|
34508
35067
|
log(`[${this.provider.displayName}] Response status: ${response.status}`);
|
|
34509
35068
|
this.capturePlanUsage(response);
|
|
34510
35069
|
if (!response.ok) {
|
|
34511
|
-
if (response.status >= 400 && response.status < 500
|
|
34512
|
-
const
|
|
34513
|
-
const
|
|
35070
|
+
if (response.status >= 400 && response.status < 500) {
|
|
35071
|
+
const candidates = [this.modelAdapter, this.getAdapter()].filter((a, i, all) => !!a?.recoverFromRejection && all.indexOf(a) === i);
|
|
35072
|
+
const errorText = candidates.length > 0 ? await response.clone().text() : "";
|
|
35073
|
+
let recovery = null;
|
|
35074
|
+
for (const candidate of candidates) {
|
|
35075
|
+
recovery = candidate.recoverFromRejection(requestPayload, errorText);
|
|
35076
|
+
if (recovery)
|
|
35077
|
+
break;
|
|
35078
|
+
}
|
|
34514
35079
|
if (recovery) {
|
|
34515
35080
|
log(`[${this.provider.displayName}] Parameter rejected \u2014 retrying: ${recovery.note}`);
|
|
34516
35081
|
requestPayload = recovery.payload;
|
|
@@ -34690,7 +35255,8 @@ class ComposedHandler {
|
|
|
34690
35255
|
providerDisplayName: this.provider.displayName,
|
|
34691
35256
|
status: response.status,
|
|
34692
35257
|
hint,
|
|
34693
|
-
providerMessage: providerMsg
|
|
35258
|
+
providerMessage: providerMsg,
|
|
35259
|
+
leadPhrase: isContextOverflowError(response.status, errorText) ? CONTEXT_OVERFLOW_PHRASE : undefined
|
|
34694
35260
|
});
|
|
34695
35261
|
return c.json(wrapAnthropicError(400, surfaced, "invalid_request_error", response.status), 400);
|
|
34696
35262
|
}
|
|
@@ -34913,20 +35479,20 @@ class ComposedHandler {
|
|
|
34913
35479
|
}
|
|
34914
35480
|
handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete, onApiError, behaviorSession) {
|
|
34915
35481
|
let pendingOnComplete = onComplete;
|
|
34916
|
-
const onTokenUpdate = (input, output) => {
|
|
35482
|
+
const onTokenUpdate = (input, output, detail) => {
|
|
34917
35483
|
const strategy = this.options.tokenStrategy || "standard";
|
|
34918
35484
|
switch (strategy) {
|
|
34919
35485
|
case "accumulate-both":
|
|
34920
|
-
this.tokenTracker.accumulateBoth(input, output);
|
|
35486
|
+
this.tokenTracker.accumulateBoth(input, output, detail);
|
|
34921
35487
|
break;
|
|
34922
35488
|
case "delta-aware":
|
|
34923
|
-
this.tokenTracker.updateWithDelta(input, output);
|
|
35489
|
+
this.tokenTracker.updateWithDelta(input, output, detail);
|
|
34924
35490
|
break;
|
|
34925
35491
|
case "local":
|
|
34926
|
-
this.tokenTracker.updateLocal(input, output);
|
|
35492
|
+
this.tokenTracker.updateLocal(input, output, detail);
|
|
34927
35493
|
break;
|
|
34928
35494
|
default:
|
|
34929
|
-
this.tokenTracker.update(input, output);
|
|
35495
|
+
this.tokenTracker.update(input, output, detail);
|
|
34930
35496
|
break;
|
|
34931
35497
|
}
|
|
34932
35498
|
if (pendingOnComplete) {
|
|
@@ -34955,7 +35521,7 @@ class ComposedHandler {
|
|
|
34955
35521
|
return createResponsesStreamHandler(c, response, {
|
|
34956
35522
|
modelName: this.bareModelName,
|
|
34957
35523
|
onTokenUpdate,
|
|
34958
|
-
toolNameMap
|
|
35524
|
+
toolNameMap,
|
|
34959
35525
|
contextWindow: lookupModelForProvider(this.bareModelName, this.provider.name),
|
|
34960
35526
|
onApiError,
|
|
34961
35527
|
priorInputTokens,
|
|
@@ -35111,6 +35677,9 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429)
|
|
|
35111
35677
|
}
|
|
35112
35678
|
return "Request format may be incompatible with provider.";
|
|
35113
35679
|
}
|
|
35680
|
+
if (isContextOverflowError(status, errorText)) {
|
|
35681
|
+
return "Input too large. Reduce message history or use a larger-context model.";
|
|
35682
|
+
}
|
|
35114
35683
|
if (status >= 500) {
|
|
35115
35684
|
return "Server error \u2014 retry after a brief wait.";
|
|
35116
35685
|
}
|
|
@@ -42866,8 +43435,10 @@ function accountStreamEvent(rawEvent) {
|
|
|
42866
43435
|
if (typeof text === "string" && text.length > 0) {
|
|
42867
43436
|
contentDelta = true;
|
|
42868
43437
|
textChars = text.length;
|
|
42869
|
-
} else if (parsed?.type === "content_block_delta"
|
|
43438
|
+
} else if (parsed?.type === "content_block_delta") {
|
|
42870
43439
|
contentDelta = true;
|
|
43440
|
+
} else if (parsed?.type === "content_block_start") {
|
|
43441
|
+
contentDelta = parsed.content_block?.type === "tool_use";
|
|
42871
43442
|
}
|
|
42872
43443
|
const outputTokens = parsed?.usage?.output_tokens ?? parsed?.message?.usage?.output_tokens ?? parsed?.usage?.completion_tokens;
|
|
42873
43444
|
const stopReason = parsed?.delta?.stop_reason ?? (Array.isArray(parsed?.choices) ? parsed.choices[0]?.finish_reason : undefined);
|
|
@@ -44591,6 +45162,7 @@ var init_cors = () => {};
|
|
|
44591
45162
|
// src/adapters/local-adapter.ts
|
|
44592
45163
|
var LocalModelAdapter;
|
|
44593
45164
|
var init_local_adapter = __esm(() => {
|
|
45165
|
+
init_openai_tools();
|
|
44594
45166
|
init_logger();
|
|
44595
45167
|
init_base_api_format();
|
|
44596
45168
|
init_dialect_manager();
|
|
@@ -44657,26 +45229,26 @@ ${messages[0].content}`;
|
|
|
44657
45229
|
tools: tools.length > 0 ? tools : undefined,
|
|
44658
45230
|
stream_options: { include_usage: true }
|
|
44659
45231
|
};
|
|
44660
|
-
if (
|
|
44661
|
-
const
|
|
44662
|
-
if (
|
|
44663
|
-
payload.tool_choice =
|
|
44664
|
-
} else if (type === "auto" || type === "none") {
|
|
44665
|
-
payload.tool_choice = type;
|
|
45232
|
+
if (tools.length > 0) {
|
|
45233
|
+
const toolChoice = mapToolChoiceToOpenAI(claudeRequest.tool_choice);
|
|
45234
|
+
if (toolChoice !== undefined) {
|
|
45235
|
+
payload.tool_choice = toolChoice;
|
|
44666
45236
|
}
|
|
44667
45237
|
}
|
|
45238
|
+
this.applyOpenAISamplingParams(payload, claudeRequest);
|
|
44668
45239
|
return payload;
|
|
44669
45240
|
}
|
|
44670
45241
|
prepareRequestCommon(request, originalRequest) {
|
|
44671
45242
|
this.innerAdapter.prepareRequest(request, originalRequest);
|
|
44672
|
-
for (const [k, v] of this.innerAdapter.getToolNameMap()) {
|
|
44673
|
-
this.toolNameMap.set(k, v);
|
|
44674
|
-
}
|
|
44675
45243
|
delete request.enable_thinking;
|
|
44676
45244
|
delete request.thinking_budget;
|
|
44677
45245
|
delete request.thinking;
|
|
44678
45246
|
return request;
|
|
44679
45247
|
}
|
|
45248
|
+
setResponseWireFormat(format) {
|
|
45249
|
+
super.setResponseWireFormat(format);
|
|
45250
|
+
this.innerAdapter.setResponseWireFormat(format);
|
|
45251
|
+
}
|
|
44680
45252
|
getToolNameMap() {
|
|
44681
45253
|
const map = new Map(super.getToolNameMap());
|
|
44682
45254
|
for (const [k, v] of this.innerAdapter.getToolNameMap()) {
|
|
@@ -44835,19 +45407,20 @@ ${text}`;
|
|
|
44835
45407
|
if (claudeRequest.thinking) {
|
|
44836
45408
|
payload.thinking = claudeRequest.thinking;
|
|
44837
45409
|
}
|
|
44838
|
-
|
|
44839
|
-
|
|
44840
|
-
|
|
44841
|
-
payload.tool_choice = { type: "function", function: { name } };
|
|
44842
|
-
} else if (type === "auto" || type === "none") {
|
|
44843
|
-
payload.tool_choice = type;
|
|
44844
|
-
}
|
|
45410
|
+
const toolChoice = mapToolChoiceToOpenAI(claudeRequest.tool_choice);
|
|
45411
|
+
if (toolChoice !== undefined) {
|
|
45412
|
+
payload.tool_choice = toolChoice;
|
|
44845
45413
|
}
|
|
45414
|
+
this.applyOpenAISamplingParams(payload, claudeRequest);
|
|
44846
45415
|
return payload;
|
|
44847
45416
|
}
|
|
44848
45417
|
prepareRequestCommon(request, originalRequest) {
|
|
44849
45418
|
return this.innerAdapter.prepareRequest(request, originalRequest);
|
|
44850
45419
|
}
|
|
45420
|
+
setResponseWireFormat(format) {
|
|
45421
|
+
super.setResponseWireFormat(format);
|
|
45422
|
+
this.innerAdapter.setResponseWireFormat(format);
|
|
45423
|
+
}
|
|
44851
45424
|
getToolNameMap() {
|
|
44852
45425
|
const map = new Map(super.getToolNameMap());
|
|
44853
45426
|
for (const [k, v] of this.innerAdapter.getToolNameMap()) {
|