@ai-sdk-tool/parser 3.3.2 → 4.0.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/README.md +7 -0
- package/dist/{chunk-OUGMLYAW.js → chunk-2KK5BDZF.js} +373 -8
- package/dist/chunk-2KK5BDZF.js.map +1 -0
- package/dist/{chunk-ZDBNJWLY.js → chunk-CXWS24JX.js} +2 -2
- package/dist/{chunk-5WKXBBCU.js → chunk-ERJKQKCR.js} +2059 -293
- package/dist/chunk-ERJKQKCR.js.map +1 -0
- package/dist/community.cjs +2496 -367
- package/dist/community.cjs.map +1 -1
- package/dist/community.js +3 -3
- package/dist/index.cjs +2496 -367
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -14
- package/dist/index.d.ts +22 -14
- package/dist/index.js +3 -3
- package/dist/rxml.cjs +377 -12
- package/dist/rxml.cjs.map +1 -1
- package/dist/rxml.js +2 -2
- package/dist/schema-coerce.cjs +372 -7
- package/dist/schema-coerce.cjs.map +1 -1
- package/dist/schema-coerce.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-5WKXBBCU.js.map +0 -1
- package/dist/chunk-OUGMLYAW.js.map +0 -1
- /package/dist/{chunk-ZDBNJWLY.js.map → chunk-CXWS24JX.js.map} +0 -0
|
@@ -2,13 +2,15 @@ import {
|
|
|
2
2
|
escapeRegExp,
|
|
3
3
|
parse as parse2,
|
|
4
4
|
stringify
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CXWS24JX.js";
|
|
6
6
|
import {
|
|
7
7
|
parse
|
|
8
8
|
} from "./chunk-IX4FJELL.js";
|
|
9
9
|
import {
|
|
10
|
-
coerceBySchema
|
|
11
|
-
|
|
10
|
+
coerceBySchema,
|
|
11
|
+
getSchemaType,
|
|
12
|
+
unwrapJsonSchema
|
|
13
|
+
} from "./chunk-2KK5BDZF.js";
|
|
12
14
|
|
|
13
15
|
// src/core/utils/debug.ts
|
|
14
16
|
var LINE_SPLIT_REGEX = /\r?\n/;
|
|
@@ -185,7 +187,25 @@ function getPotentialStartIndex(text, searchedText) {
|
|
|
185
187
|
|
|
186
188
|
// src/core/utils/id.ts
|
|
187
189
|
function generateId() {
|
|
188
|
-
return
|
|
190
|
+
return crypto.randomUUID().replace(/-/g, "").slice(0, 13);
|
|
191
|
+
}
|
|
192
|
+
var TOOL_CALL_ID_PREFIX = "call_";
|
|
193
|
+
var TOOL_CALL_ID_BODY_LENGTH = 24;
|
|
194
|
+
var TOOL_CALL_ID_ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
195
|
+
function randomAlphaNumeric(length) {
|
|
196
|
+
var _a;
|
|
197
|
+
const bytes = new Uint8Array(length);
|
|
198
|
+
crypto.getRandomValues(bytes);
|
|
199
|
+
let out = "";
|
|
200
|
+
for (let i = 0; i < length; i += 1) {
|
|
201
|
+
const byte = bytes[i];
|
|
202
|
+
const index = (byte != null ? byte : 0) % TOOL_CALL_ID_ALPHANUM.length;
|
|
203
|
+
out += (_a = TOOL_CALL_ID_ALPHANUM[index]) != null ? _a : "0";
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
function generateToolCallId() {
|
|
208
|
+
return `${TOOL_CALL_ID_PREFIX}${randomAlphaNumeric(TOOL_CALL_ID_BODY_LENGTH)}`;
|
|
189
209
|
}
|
|
190
210
|
|
|
191
211
|
// src/core/utils/protocol-utils.ts
|
|
@@ -194,17 +214,55 @@ function addTextSegment(text, processedElements) {
|
|
|
194
214
|
processedElements.push({ type: "text", text });
|
|
195
215
|
}
|
|
196
216
|
}
|
|
217
|
+
function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
218
|
+
return (controller, text) => {
|
|
219
|
+
const content = text;
|
|
220
|
+
if (content) {
|
|
221
|
+
if (!getCurrentTextId()) {
|
|
222
|
+
const newId = generateId();
|
|
223
|
+
setCurrentTextId(newId);
|
|
224
|
+
controller.enqueue({
|
|
225
|
+
type: "text-start",
|
|
226
|
+
id: newId
|
|
227
|
+
});
|
|
228
|
+
setHasEmittedTextStart(true);
|
|
229
|
+
}
|
|
230
|
+
controller.enqueue({
|
|
231
|
+
type: "text-delta",
|
|
232
|
+
id: getCurrentTextId(),
|
|
233
|
+
delta: content
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const currentTextId = getCurrentTextId();
|
|
237
|
+
if (currentTextId && !text) {
|
|
238
|
+
if (getHasEmittedTextStart()) {
|
|
239
|
+
controller.enqueue({
|
|
240
|
+
type: "text-end",
|
|
241
|
+
id: currentTextId
|
|
242
|
+
});
|
|
243
|
+
setHasEmittedTextStart(false);
|
|
244
|
+
}
|
|
245
|
+
setCurrentTextId(null);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
197
249
|
|
|
198
250
|
// src/core/protocols/json-protocol.ts
|
|
251
|
+
function shouldEmitRawToolCallTextOnError(options) {
|
|
252
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
253
|
+
}
|
|
254
|
+
function canonicalizeToolInput(argumentsValue) {
|
|
255
|
+
return JSON.stringify(argumentsValue != null ? argumentsValue : {});
|
|
256
|
+
}
|
|
199
257
|
function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
|
|
200
|
-
var _a
|
|
258
|
+
var _a;
|
|
201
259
|
try {
|
|
202
260
|
const parsedToolCall = parse(toolCallJson);
|
|
203
261
|
processedElements.push({
|
|
204
262
|
type: "tool-call",
|
|
205
|
-
toolCallId:
|
|
263
|
+
toolCallId: generateToolCallId(),
|
|
206
264
|
toolName: parsedToolCall.name,
|
|
207
|
-
input:
|
|
265
|
+
input: canonicalizeToolInput(parsedToolCall.arguments)
|
|
208
266
|
});
|
|
209
267
|
} catch (error) {
|
|
210
268
|
logParseFailure({
|
|
@@ -213,7 +271,7 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
|
|
|
213
271
|
snippet: fullMatch,
|
|
214
272
|
error
|
|
215
273
|
});
|
|
216
|
-
(
|
|
274
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
217
275
|
options,
|
|
218
276
|
"Could not process JSON tool call, keeping original text.",
|
|
219
277
|
{ toolCall: fullMatch, error }
|
|
@@ -234,6 +292,293 @@ function processMatchedToolCall(context) {
|
|
|
234
292
|
}
|
|
235
293
|
return startIndex + match[0].length;
|
|
236
294
|
}
|
|
295
|
+
var WHITESPACE_JSON_REGEX = /\s/;
|
|
296
|
+
function skipJsonWhitespace(text, fromIndex) {
|
|
297
|
+
let index = fromIndex;
|
|
298
|
+
while (index < text.length && WHITESPACE_JSON_REGEX.test(text[index])) {
|
|
299
|
+
index += 1;
|
|
300
|
+
}
|
|
301
|
+
return index;
|
|
302
|
+
}
|
|
303
|
+
function findTopLevelPropertyValueStart(text, property) {
|
|
304
|
+
const objectStart = skipJsonWhitespace(text, 0);
|
|
305
|
+
if (objectStart >= text.length || text.charAt(objectStart) !== "{") {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
let depth = 0;
|
|
309
|
+
let inString = false;
|
|
310
|
+
let escaping = false;
|
|
311
|
+
for (let index = objectStart; index < text.length; index += 1) {
|
|
312
|
+
const char = text.charAt(index);
|
|
313
|
+
if (inString) {
|
|
314
|
+
if (escaping) {
|
|
315
|
+
escaping = false;
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (char === "\\") {
|
|
319
|
+
escaping = true;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (char === '"') {
|
|
323
|
+
inString = false;
|
|
324
|
+
}
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (char === "{") {
|
|
328
|
+
depth += 1;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (char === "}") {
|
|
332
|
+
depth = Math.max(0, depth - 1);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (char !== '"') {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (depth !== 1) {
|
|
339
|
+
inString = true;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const keyStart = index + 1;
|
|
343
|
+
let keyEnd = keyStart;
|
|
344
|
+
let keyEscaped = false;
|
|
345
|
+
while (keyEnd < text.length) {
|
|
346
|
+
const keyChar = text.charAt(keyEnd);
|
|
347
|
+
if (keyEscaped) {
|
|
348
|
+
keyEscaped = false;
|
|
349
|
+
} else if (keyChar === "\\") {
|
|
350
|
+
keyEscaped = true;
|
|
351
|
+
} else if (keyChar === '"') {
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
keyEnd += 1;
|
|
355
|
+
}
|
|
356
|
+
if (keyEnd >= text.length || text.charAt(keyEnd) !== '"') {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
const key = text.slice(keyStart, keyEnd);
|
|
360
|
+
let valueCursor = skipJsonWhitespace(text, keyEnd + 1);
|
|
361
|
+
if (valueCursor >= text.length || text.charAt(valueCursor) !== ":") {
|
|
362
|
+
index = keyEnd;
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
valueCursor = skipJsonWhitespace(text, valueCursor + 1);
|
|
366
|
+
if (key === property) {
|
|
367
|
+
return valueCursor < text.length ? valueCursor : null;
|
|
368
|
+
}
|
|
369
|
+
index = valueCursor - 1;
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
function extractTopLevelStringProperty(text, property) {
|
|
374
|
+
const valueStart = findTopLevelPropertyValueStart(text, property);
|
|
375
|
+
if (valueStart == null || valueStart >= text.length) {
|
|
376
|
+
return void 0;
|
|
377
|
+
}
|
|
378
|
+
if (text.charAt(valueStart) !== '"') {
|
|
379
|
+
return void 0;
|
|
380
|
+
}
|
|
381
|
+
let valueEnd = valueStart + 1;
|
|
382
|
+
let escaped = false;
|
|
383
|
+
while (valueEnd < text.length) {
|
|
384
|
+
const char = text.charAt(valueEnd);
|
|
385
|
+
if (escaped) {
|
|
386
|
+
escaped = false;
|
|
387
|
+
} else if (char === "\\") {
|
|
388
|
+
escaped = true;
|
|
389
|
+
} else if (char === '"') {
|
|
390
|
+
return text.slice(valueStart + 1, valueEnd);
|
|
391
|
+
}
|
|
392
|
+
valueEnd += 1;
|
|
393
|
+
}
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
function extractJsonValueSlice(text, valueStart) {
|
|
397
|
+
if (valueStart >= text.length) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
const first = text.charAt(valueStart);
|
|
401
|
+
if (first === "{" || first === "[") {
|
|
402
|
+
const stack = [first];
|
|
403
|
+
let inString = false;
|
|
404
|
+
let escaped = false;
|
|
405
|
+
for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
|
|
406
|
+
const char = text.charAt(index2);
|
|
407
|
+
if (inString) {
|
|
408
|
+
if (escaped) {
|
|
409
|
+
escaped = false;
|
|
410
|
+
} else if (char === "\\") {
|
|
411
|
+
escaped = true;
|
|
412
|
+
} else if (char === '"') {
|
|
413
|
+
inString = false;
|
|
414
|
+
}
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (char === '"') {
|
|
418
|
+
inString = true;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (char === "{" || char === "[") {
|
|
422
|
+
stack.push(char);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (char === "}" || char === "]") {
|
|
426
|
+
const open = stack.at(-1);
|
|
427
|
+
if (open === "{" && char === "}" || open === "[" && char === "]") {
|
|
428
|
+
stack.pop();
|
|
429
|
+
if (stack.length === 0) {
|
|
430
|
+
return {
|
|
431
|
+
text: text.slice(valueStart, index2 + 1),
|
|
432
|
+
complete: true
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return {
|
|
439
|
+
text: text.slice(valueStart),
|
|
440
|
+
complete: false
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
if (first === '"') {
|
|
444
|
+
let escaped = false;
|
|
445
|
+
for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
|
|
446
|
+
const char = text.charAt(index2);
|
|
447
|
+
if (escaped) {
|
|
448
|
+
escaped = false;
|
|
449
|
+
} else if (char === "\\") {
|
|
450
|
+
escaped = true;
|
|
451
|
+
} else if (char === '"') {
|
|
452
|
+
return {
|
|
453
|
+
text: text.slice(valueStart, index2 + 1),
|
|
454
|
+
complete: true
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
text: text.slice(valueStart),
|
|
460
|
+
complete: false
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
let index = valueStart;
|
|
464
|
+
while (index < text.length) {
|
|
465
|
+
const char = text.charAt(index);
|
|
466
|
+
if (char === "," || char === "}" || WHITESPACE_JSON_REGEX.test(char)) {
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
index += 1;
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
text: text.slice(valueStart, index),
|
|
473
|
+
complete: index < text.length
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function extractStreamingToolCallProgress(toolCallJson) {
|
|
477
|
+
var _a;
|
|
478
|
+
const toolName = extractTopLevelStringProperty(toolCallJson, "name");
|
|
479
|
+
const argsValueStart = findTopLevelPropertyValueStart(
|
|
480
|
+
toolCallJson,
|
|
481
|
+
"arguments"
|
|
482
|
+
);
|
|
483
|
+
if (argsValueStart == null) {
|
|
484
|
+
return {
|
|
485
|
+
toolName,
|
|
486
|
+
argumentsText: void 0,
|
|
487
|
+
argumentsComplete: false
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const argsSlice = extractJsonValueSlice(toolCallJson, argsValueStart);
|
|
491
|
+
return {
|
|
492
|
+
toolName,
|
|
493
|
+
argumentsText: argsSlice == null ? void 0 : argsSlice.text,
|
|
494
|
+
argumentsComplete: (_a = argsSlice == null ? void 0 : argsSlice.complete) != null ? _a : false
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function ensureToolInputStart(state, controller, toolName) {
|
|
498
|
+
if (!state.activeToolInput) {
|
|
499
|
+
const id = generateToolCallId();
|
|
500
|
+
state.activeToolInput = {
|
|
501
|
+
id,
|
|
502
|
+
toolName,
|
|
503
|
+
emittedInput: ""
|
|
504
|
+
};
|
|
505
|
+
controller.enqueue({
|
|
506
|
+
type: "tool-input-start",
|
|
507
|
+
id,
|
|
508
|
+
toolName
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function emitToolInputDelta(state, controller, fullInput) {
|
|
513
|
+
const active = state.activeToolInput;
|
|
514
|
+
if (!active) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (!fullInput.startsWith(active.emittedInput)) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const delta = fullInput.slice(active.emittedInput.length);
|
|
521
|
+
if (delta.length === 0) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
controller.enqueue({
|
|
525
|
+
type: "tool-input-delta",
|
|
526
|
+
id: active.id,
|
|
527
|
+
delta
|
|
528
|
+
});
|
|
529
|
+
active.emittedInput = fullInput;
|
|
530
|
+
}
|
|
531
|
+
function closeToolInput(state, controller) {
|
|
532
|
+
if (!state.activeToolInput) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
controller.enqueue({
|
|
536
|
+
type: "tool-input-end",
|
|
537
|
+
id: state.activeToolInput.id
|
|
538
|
+
});
|
|
539
|
+
state.activeToolInput = null;
|
|
540
|
+
}
|
|
541
|
+
function emitToolCallFromParsed(state, controller, parsedToolCall) {
|
|
542
|
+
var _a, _b, _c, _d;
|
|
543
|
+
closeTextBlock(state, controller);
|
|
544
|
+
const toolName = typeof parsedToolCall.name === "string" ? parsedToolCall.name : (_b = (_a = state.activeToolInput) == null ? void 0 : _a.toolName) != null ? _b : "unknown";
|
|
545
|
+
const input = canonicalizeToolInput(parsedToolCall.arguments);
|
|
546
|
+
ensureToolInputStart(state, controller, toolName);
|
|
547
|
+
emitToolInputDelta(state, controller, input);
|
|
548
|
+
const toolCallId = (_d = (_c = state.activeToolInput) == null ? void 0 : _c.id) != null ? _d : generateToolCallId();
|
|
549
|
+
closeToolInput(state, controller);
|
|
550
|
+
controller.enqueue({
|
|
551
|
+
type: "tool-call",
|
|
552
|
+
toolCallId,
|
|
553
|
+
toolName,
|
|
554
|
+
input
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
function canonicalizeArgumentsProgressInput(progress) {
|
|
558
|
+
if (progress.argumentsText === void 0 || !progress.argumentsComplete) {
|
|
559
|
+
return void 0;
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
const parsedArguments = parse(progress.argumentsText);
|
|
563
|
+
return canonicalizeToolInput(parsedArguments);
|
|
564
|
+
} catch (e) {
|
|
565
|
+
return void 0;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function emitToolInputProgress(state, controller) {
|
|
569
|
+
if (!(state.isInsideToolCall && state.currentToolCallJson)) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const progress = extractStreamingToolCallProgress(state.currentToolCallJson);
|
|
573
|
+
if (!progress.toolName) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
ensureToolInputStart(state, controller, progress.toolName);
|
|
577
|
+
const canonicalProgressInput = canonicalizeArgumentsProgressInput(progress);
|
|
578
|
+
if (canonicalProgressInput !== void 0) {
|
|
579
|
+
emitToolInputDelta(state, controller, canonicalProgressInput);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
237
582
|
function flushBuffer(state, controller, toolCallStart) {
|
|
238
583
|
if (state.buffer.length === 0) {
|
|
239
584
|
return;
|
|
@@ -264,44 +609,77 @@ function closeTextBlock(state, controller) {
|
|
|
264
609
|
state.hasEmittedTextStart = false;
|
|
265
610
|
}
|
|
266
611
|
}
|
|
267
|
-
function emitIncompleteToolCall(state, controller, toolCallStart) {
|
|
268
|
-
|
|
612
|
+
function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, options) {
|
|
613
|
+
var _a;
|
|
614
|
+
if (!state.currentToolCallJson && trailingBuffer.length === 0) {
|
|
615
|
+
state.isInsideToolCall = false;
|
|
269
616
|
return;
|
|
270
617
|
}
|
|
618
|
+
if (state.currentToolCallJson) {
|
|
619
|
+
try {
|
|
620
|
+
const parsedToolCall = parse(state.currentToolCallJson);
|
|
621
|
+
emitToolCallFromParsed(state, controller, parsedToolCall);
|
|
622
|
+
state.currentToolCallJson = "";
|
|
623
|
+
state.isInsideToolCall = false;
|
|
624
|
+
return;
|
|
625
|
+
} catch (e) {
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
const rawToolCallContent = `${state.currentToolCallJson}${trailingBuffer}`;
|
|
629
|
+
const errorContent = `${toolCallStart}${rawToolCallContent}`;
|
|
630
|
+
const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
|
|
271
631
|
logParseFailure({
|
|
272
632
|
phase: "stream",
|
|
273
|
-
reason: "Incomplete streaming tool call segment emitted as text",
|
|
274
|
-
snippet:
|
|
275
|
-
});
|
|
276
|
-
const errorId = generateId();
|
|
277
|
-
const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
|
|
278
|
-
controller.enqueue({
|
|
279
|
-
type: "text-start",
|
|
280
|
-
id: errorId
|
|
281
|
-
});
|
|
282
|
-
controller.enqueue({
|
|
283
|
-
type: "text-delta",
|
|
284
|
-
id: errorId,
|
|
285
|
-
delta: errorContent
|
|
286
|
-
});
|
|
287
|
-
controller.enqueue({
|
|
288
|
-
type: "text-end",
|
|
289
|
-
id: errorId
|
|
633
|
+
reason: shouldEmitRawFallback ? "Incomplete streaming tool call segment emitted as text" : "Incomplete streaming tool call segment suppressed without raw text fallback",
|
|
634
|
+
snippet: errorContent
|
|
290
635
|
});
|
|
636
|
+
if (shouldEmitRawFallback) {
|
|
637
|
+
const errorId = generateId();
|
|
638
|
+
controller.enqueue({
|
|
639
|
+
type: "text-start",
|
|
640
|
+
id: errorId
|
|
641
|
+
});
|
|
642
|
+
controller.enqueue({
|
|
643
|
+
type: "text-delta",
|
|
644
|
+
id: errorId,
|
|
645
|
+
delta: errorContent
|
|
646
|
+
});
|
|
647
|
+
controller.enqueue({
|
|
648
|
+
type: "text-end",
|
|
649
|
+
id: errorId
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
closeToolInput(state, controller);
|
|
653
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
654
|
+
options,
|
|
655
|
+
shouldEmitRawFallback ? "Could not complete streaming JSON tool call at finish; emitting original text." : "Could not complete streaming JSON tool call at finish.",
|
|
656
|
+
{ toolCall: errorContent }
|
|
657
|
+
);
|
|
291
658
|
state.currentToolCallJson = "";
|
|
659
|
+
state.isInsideToolCall = false;
|
|
292
660
|
}
|
|
293
|
-
function handleFinishChunk(state, controller, toolCallStart, chunk) {
|
|
294
|
-
if (state.
|
|
661
|
+
function handleFinishChunk(state, controller, toolCallStart, options, chunk) {
|
|
662
|
+
if (state.isInsideToolCall) {
|
|
663
|
+
const trailingBuffer = state.buffer;
|
|
664
|
+
state.buffer = "";
|
|
665
|
+
emitIncompleteToolCall(
|
|
666
|
+
state,
|
|
667
|
+
controller,
|
|
668
|
+
toolCallStart,
|
|
669
|
+
trailingBuffer,
|
|
670
|
+
options
|
|
671
|
+
);
|
|
672
|
+
} else if (state.buffer.length > 0) {
|
|
295
673
|
flushBuffer(state, controller, toolCallStart);
|
|
296
674
|
}
|
|
297
675
|
closeTextBlock(state, controller);
|
|
298
|
-
emitIncompleteToolCall(state, controller, toolCallStart);
|
|
299
676
|
controller.enqueue(chunk);
|
|
300
677
|
}
|
|
301
678
|
function publishText(text, state, controller) {
|
|
302
679
|
if (state.isInsideToolCall) {
|
|
303
680
|
closeTextBlock(state, controller);
|
|
304
681
|
state.currentToolCallJson += text;
|
|
682
|
+
emitToolInputProgress(state, controller);
|
|
305
683
|
} else if (text.length > 0) {
|
|
306
684
|
if (!state.currentTextId) {
|
|
307
685
|
state.currentTextId = generateId();
|
|
@@ -319,42 +697,40 @@ function publishText(text, state, controller) {
|
|
|
319
697
|
}
|
|
320
698
|
}
|
|
321
699
|
function emitToolCall(context) {
|
|
322
|
-
var _a
|
|
700
|
+
var _a;
|
|
323
701
|
const { state, controller, toolCallStart, toolCallEnd, options } = context;
|
|
324
702
|
try {
|
|
325
703
|
const parsedToolCall = parse(state.currentToolCallJson);
|
|
326
|
-
|
|
327
|
-
controller.enqueue({
|
|
328
|
-
type: "tool-call",
|
|
329
|
-
toolCallId: generateId(),
|
|
330
|
-
toolName: parsedToolCall.name,
|
|
331
|
-
input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
|
|
332
|
-
});
|
|
704
|
+
emitToolCallFromParsed(state, controller, parsedToolCall);
|
|
333
705
|
} catch (error) {
|
|
706
|
+
const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
|
|
707
|
+
const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
|
|
334
708
|
logParseFailure({
|
|
335
709
|
phase: "stream",
|
|
336
710
|
reason: "Failed to parse streaming tool call JSON segment",
|
|
337
|
-
snippet:
|
|
711
|
+
snippet: errorContent,
|
|
338
712
|
error
|
|
339
713
|
});
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
714
|
+
if (shouldEmitRawFallback) {
|
|
715
|
+
const errorId = generateId();
|
|
716
|
+
controller.enqueue({
|
|
717
|
+
type: "text-start",
|
|
718
|
+
id: errorId
|
|
719
|
+
});
|
|
720
|
+
controller.enqueue({
|
|
721
|
+
type: "text-delta",
|
|
722
|
+
id: errorId,
|
|
723
|
+
delta: errorContent
|
|
724
|
+
});
|
|
725
|
+
controller.enqueue({
|
|
726
|
+
type: "text-end",
|
|
727
|
+
id: errorId
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
closeToolInput(state, controller);
|
|
731
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
356
732
|
options,
|
|
357
|
-
"Could not process streaming JSON tool call; emitting original text.",
|
|
733
|
+
shouldEmitRawFallback ? "Could not process streaming JSON tool call; emitting original text." : "Could not process streaming JSON tool call.",
|
|
358
734
|
{
|
|
359
735
|
toolCall: errorContent
|
|
360
736
|
}
|
|
@@ -370,6 +746,7 @@ function processTagMatch(context) {
|
|
|
370
746
|
} else {
|
|
371
747
|
state.currentToolCallJson = "";
|
|
372
748
|
state.isInsideToolCall = true;
|
|
749
|
+
state.activeToolInput = null;
|
|
373
750
|
}
|
|
374
751
|
}
|
|
375
752
|
function processBufferTags(context) {
|
|
@@ -392,8 +769,16 @@ function processBufferTags(context) {
|
|
|
392
769
|
);
|
|
393
770
|
}
|
|
394
771
|
}
|
|
395
|
-
function handlePartialTag(state, controller, toolCallStart) {
|
|
772
|
+
function handlePartialTag(state, controller, toolCallStart, toolCallEnd) {
|
|
396
773
|
if (state.isInsideToolCall) {
|
|
774
|
+
const potentialEndIndex = getPotentialStartIndex(state.buffer, toolCallEnd);
|
|
775
|
+
if (potentialEndIndex != null && potentialEndIndex + toolCallEnd.length > state.buffer.length) {
|
|
776
|
+
publishText(state.buffer.slice(0, potentialEndIndex), state, controller);
|
|
777
|
+
state.buffer = state.buffer.slice(potentialEndIndex);
|
|
778
|
+
} else {
|
|
779
|
+
publishText(state.buffer, state, controller);
|
|
780
|
+
state.buffer = "";
|
|
781
|
+
}
|
|
397
782
|
return;
|
|
398
783
|
}
|
|
399
784
|
const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
|
|
@@ -466,13 +851,14 @@ var jsonProtocol = ({
|
|
|
466
851
|
buffer: "",
|
|
467
852
|
currentToolCallJson: "",
|
|
468
853
|
currentTextId: null,
|
|
469
|
-
hasEmittedTextStart: false
|
|
854
|
+
hasEmittedTextStart: false,
|
|
855
|
+
activeToolInput: null
|
|
470
856
|
};
|
|
471
857
|
return new TransformStream({
|
|
472
858
|
transform(chunk, controller) {
|
|
473
859
|
var _a;
|
|
474
860
|
if (chunk.type === "finish") {
|
|
475
|
-
handleFinishChunk(state, controller, toolCallStart, chunk);
|
|
861
|
+
handleFinishChunk(state, controller, toolCallStart, options, chunk);
|
|
476
862
|
return;
|
|
477
863
|
}
|
|
478
864
|
if (chunk.type !== "text-delta") {
|
|
@@ -488,7 +874,7 @@ var jsonProtocol = ({
|
|
|
488
874
|
toolCallEnd,
|
|
489
875
|
options
|
|
490
876
|
});
|
|
491
|
-
handlePartialTag(state, controller, toolCallStart);
|
|
877
|
+
handlePartialTag(state, controller, toolCallStart, toolCallEnd);
|
|
492
878
|
}
|
|
493
879
|
});
|
|
494
880
|
},
|
|
@@ -518,11 +904,112 @@ function isTCMProtocolFactory(protocol) {
|
|
|
518
904
|
var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
|
|
519
905
|
var WHITESPACE_REGEX = /\s/;
|
|
520
906
|
|
|
907
|
+
// src/core/utils/streamed-tool-input-delta.ts
|
|
908
|
+
function emitDelta({
|
|
909
|
+
controller,
|
|
910
|
+
id,
|
|
911
|
+
state,
|
|
912
|
+
nextInput
|
|
913
|
+
}) {
|
|
914
|
+
if (!nextInput.startsWith(state.emittedInput)) {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
const delta = nextInput.slice(state.emittedInput.length);
|
|
918
|
+
if (delta.length === 0) {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
controller.enqueue({
|
|
922
|
+
type: "tool-input-delta",
|
|
923
|
+
id,
|
|
924
|
+
delta
|
|
925
|
+
});
|
|
926
|
+
state.emittedInput = nextInput;
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
function toIncompleteJsonPrefix(fullJson) {
|
|
930
|
+
const trimmed = fullJson.trim();
|
|
931
|
+
let prefix = trimmed;
|
|
932
|
+
while (prefix.endsWith("}") || prefix.endsWith("]")) {
|
|
933
|
+
prefix = prefix.slice(0, -1);
|
|
934
|
+
}
|
|
935
|
+
prefix = prefix.trimEnd();
|
|
936
|
+
if (prefix.endsWith('"')) {
|
|
937
|
+
prefix = prefix.slice(0, -1);
|
|
938
|
+
}
|
|
939
|
+
if (prefix.length === 0) {
|
|
940
|
+
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
|
|
941
|
+
return trimmed.startsWith("{") ? "{" : "[";
|
|
942
|
+
}
|
|
943
|
+
if (trimmed.startsWith("]")) {
|
|
944
|
+
return "[";
|
|
945
|
+
}
|
|
946
|
+
if (trimmed.startsWith("}")) {
|
|
947
|
+
return "{";
|
|
948
|
+
}
|
|
949
|
+
if (trimmed.startsWith('"')) {
|
|
950
|
+
return '"';
|
|
951
|
+
}
|
|
952
|
+
return "{";
|
|
953
|
+
}
|
|
954
|
+
return prefix;
|
|
955
|
+
}
|
|
956
|
+
function emitPrefixDelta(params) {
|
|
957
|
+
return emitDelta({
|
|
958
|
+
...params,
|
|
959
|
+
nextInput: params.candidate
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
function emitFinalRemainder(params) {
|
|
963
|
+
var _a;
|
|
964
|
+
const result = emitDelta({
|
|
965
|
+
...params,
|
|
966
|
+
nextInput: params.finalFullJson
|
|
967
|
+
});
|
|
968
|
+
if (!result && params.state.emittedInput.length > 0) {
|
|
969
|
+
(_a = params.onMismatch) == null ? void 0 : _a.call(
|
|
970
|
+
params,
|
|
971
|
+
"Final JSON does not extend emitted tool-input prefix",
|
|
972
|
+
{
|
|
973
|
+
emittedLength: params.state.emittedInput.length,
|
|
974
|
+
finalLength: params.finalFullJson.length
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
return result;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// src/core/utils/xml-root-repair.ts
|
|
982
|
+
var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
|
|
983
|
+
function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
|
|
984
|
+
const trimmed = rawText.trim();
|
|
985
|
+
if (trimmed.length === 0) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
const match = trimmed.match(XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX);
|
|
989
|
+
if (!match) {
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
const rootTag = match[1];
|
|
993
|
+
if (!toolNames.includes(rootTag)) {
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
const body = match[2].trimEnd();
|
|
997
|
+
if (body.trim().length === 0 || body.includes(`</${rootTag}>`)) {
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
return `<${rootTag}>
|
|
1001
|
+
${body}
|
|
1002
|
+
</${rootTag}>`;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
521
1005
|
// src/core/protocols/xml-protocol.ts
|
|
522
1006
|
function getToolSchema(tools, toolName) {
|
|
523
1007
|
var _a;
|
|
524
1008
|
return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
|
|
525
1009
|
}
|
|
1010
|
+
function shouldEmitRawToolCallTextOnError2(options) {
|
|
1011
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
1012
|
+
}
|
|
526
1013
|
function processToolCall(params) {
|
|
527
1014
|
var _a, _b;
|
|
528
1015
|
const { toolCall, tools, options, text, processedElements, parseOptions } = params;
|
|
@@ -535,7 +1022,7 @@ function processToolCall(params) {
|
|
|
535
1022
|
const parsed = parse2(toolCall.content, toolSchema, parseConfig);
|
|
536
1023
|
processedElements.push({
|
|
537
1024
|
type: "tool-call",
|
|
538
|
-
toolCallId:
|
|
1025
|
+
toolCallId: generateToolCallId(),
|
|
539
1026
|
toolName: toolCall.toolName,
|
|
540
1027
|
input: JSON.stringify(parsed)
|
|
541
1028
|
});
|
|
@@ -552,6 +1039,299 @@ function processToolCall(params) {
|
|
|
552
1039
|
processedElements.push({ type: "text", text: originalCallText });
|
|
553
1040
|
}
|
|
554
1041
|
}
|
|
1042
|
+
function parseXmlTagName(rawTagBody) {
|
|
1043
|
+
let index = 0;
|
|
1044
|
+
while (index < rawTagBody.length && WHITESPACE_REGEX.test(rawTagBody[index])) {
|
|
1045
|
+
index += 1;
|
|
1046
|
+
}
|
|
1047
|
+
const nameStart = index;
|
|
1048
|
+
while (index < rawTagBody.length && NAME_CHAR_RE.test(rawTagBody.charAt(index))) {
|
|
1049
|
+
index += 1;
|
|
1050
|
+
}
|
|
1051
|
+
return rawTagBody.slice(nameStart, index);
|
|
1052
|
+
}
|
|
1053
|
+
function consumeXmlSpecialSection(fragment, ltIndex) {
|
|
1054
|
+
if (fragment.startsWith("<!--", ltIndex)) {
|
|
1055
|
+
const commentEnd = fragment.indexOf("-->", ltIndex + 4);
|
|
1056
|
+
return commentEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: commentEnd + 3 };
|
|
1057
|
+
}
|
|
1058
|
+
if (fragment.startsWith("<![CDATA[", ltIndex)) {
|
|
1059
|
+
const cdataEnd = fragment.indexOf("]]>", ltIndex + 9);
|
|
1060
|
+
return cdataEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: cdataEnd + 3 };
|
|
1061
|
+
}
|
|
1062
|
+
if (fragment.startsWith("<?", ltIndex)) {
|
|
1063
|
+
const processingEnd = fragment.indexOf("?>", ltIndex + 2);
|
|
1064
|
+
return processingEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: processingEnd + 2 };
|
|
1065
|
+
}
|
|
1066
|
+
if (fragment.startsWith("<!", ltIndex)) {
|
|
1067
|
+
const declarationEnd = fragment.indexOf(">", ltIndex + 2);
|
|
1068
|
+
return declarationEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: declarationEnd + 1 };
|
|
1069
|
+
}
|
|
1070
|
+
return { kind: "none" };
|
|
1071
|
+
}
|
|
1072
|
+
function parseXmlTagToken(fragment, ltIndex) {
|
|
1073
|
+
const gtIndex = fragment.indexOf(">", ltIndex + 1);
|
|
1074
|
+
if (gtIndex === -1) {
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
const tagBody = fragment.slice(ltIndex + 1, gtIndex).trim();
|
|
1078
|
+
if (tagBody.length === 0) {
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
if (tagBody.startsWith("/")) {
|
|
1082
|
+
const closeName = parseXmlTagName(tagBody.slice(1));
|
|
1083
|
+
if (closeName.length === 0) {
|
|
1084
|
+
return null;
|
|
1085
|
+
}
|
|
1086
|
+
return { kind: "close", name: closeName, nextPos: gtIndex + 1 };
|
|
1087
|
+
}
|
|
1088
|
+
const selfClosing = tagBody.endsWith("/");
|
|
1089
|
+
const openBody = selfClosing ? tagBody.slice(0, -1).trimEnd() : tagBody;
|
|
1090
|
+
const openName = parseXmlTagName(openBody);
|
|
1091
|
+
if (openName.length === 0) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
kind: "open",
|
|
1096
|
+
name: openName,
|
|
1097
|
+
selfClosing,
|
|
1098
|
+
nextPos: gtIndex + 1
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
function analyzeXmlFragmentForProgress(fragment) {
|
|
1102
|
+
const stack = [];
|
|
1103
|
+
const topLevelTagNames = [];
|
|
1104
|
+
let position = 0;
|
|
1105
|
+
while (position < fragment.length) {
|
|
1106
|
+
const ltIndex = fragment.indexOf("<", position);
|
|
1107
|
+
if (ltIndex === -1) {
|
|
1108
|
+
break;
|
|
1109
|
+
}
|
|
1110
|
+
const special = consumeXmlSpecialSection(fragment, ltIndex);
|
|
1111
|
+
if (special.kind === "incomplete") {
|
|
1112
|
+
return null;
|
|
1113
|
+
}
|
|
1114
|
+
if (special.kind === "consumed") {
|
|
1115
|
+
position = special.nextPos;
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
const token = parseXmlTagToken(fragment, ltIndex);
|
|
1119
|
+
if (token === null) {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
if (token.kind === "close") {
|
|
1123
|
+
const openName = stack.pop();
|
|
1124
|
+
if (!openName || openName !== token.name) {
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
position = token.nextPos;
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
if (stack.length === 0) {
|
|
1131
|
+
topLevelTagNames.push(token.name);
|
|
1132
|
+
}
|
|
1133
|
+
if (!token.selfClosing) {
|
|
1134
|
+
stack.push(token.name);
|
|
1135
|
+
}
|
|
1136
|
+
position = token.nextPos;
|
|
1137
|
+
}
|
|
1138
|
+
if (stack.length > 0) {
|
|
1139
|
+
return null;
|
|
1140
|
+
}
|
|
1141
|
+
return { topLevelTagNames };
|
|
1142
|
+
}
|
|
1143
|
+
function scanXmlFragmentTopLevelTextStep(options) {
|
|
1144
|
+
const { fragment, position, stack } = options;
|
|
1145
|
+
const ltIndex = fragment.indexOf("<", position);
|
|
1146
|
+
if (ltIndex === -1) {
|
|
1147
|
+
const trailingText = fragment.slice(position);
|
|
1148
|
+
return {
|
|
1149
|
+
kind: "done",
|
|
1150
|
+
value: stack.length === 0 && trailingText.trim().length > 0
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
const textBetweenTags = fragment.slice(position, ltIndex);
|
|
1154
|
+
if (stack.length === 0 && textBetweenTags.trim().length > 0) {
|
|
1155
|
+
return { kind: "found" };
|
|
1156
|
+
}
|
|
1157
|
+
const special = consumeXmlSpecialSection(fragment, ltIndex);
|
|
1158
|
+
if (special.kind === "incomplete") {
|
|
1159
|
+
return { kind: "invalid" };
|
|
1160
|
+
}
|
|
1161
|
+
if (special.kind === "consumed") {
|
|
1162
|
+
return { kind: "next", nextPos: special.nextPos };
|
|
1163
|
+
}
|
|
1164
|
+
const token = parseXmlTagToken(fragment, ltIndex);
|
|
1165
|
+
if (token === null) {
|
|
1166
|
+
return { kind: "invalid" };
|
|
1167
|
+
}
|
|
1168
|
+
if (token.kind === "close") {
|
|
1169
|
+
const openName = stack.pop();
|
|
1170
|
+
if (!openName || openName !== token.name) {
|
|
1171
|
+
return { kind: "invalid" };
|
|
1172
|
+
}
|
|
1173
|
+
} else if (!token.selfClosing) {
|
|
1174
|
+
stack.push(token.name);
|
|
1175
|
+
}
|
|
1176
|
+
return { kind: "next", nextPos: token.nextPos };
|
|
1177
|
+
}
|
|
1178
|
+
function hasNonWhitespaceTopLevelText(fragment) {
|
|
1179
|
+
if (!fragment.includes("<")) {
|
|
1180
|
+
return fragment.trim().length > 0;
|
|
1181
|
+
}
|
|
1182
|
+
const stack = [];
|
|
1183
|
+
let position = 0;
|
|
1184
|
+
while (position < fragment.length) {
|
|
1185
|
+
const step = scanXmlFragmentTopLevelTextStep({ fragment, position, stack });
|
|
1186
|
+
if (step.kind === "found") {
|
|
1187
|
+
return true;
|
|
1188
|
+
}
|
|
1189
|
+
if (step.kind === "invalid") {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
if (step.kind === "done") {
|
|
1193
|
+
return step.value;
|
|
1194
|
+
}
|
|
1195
|
+
position = step.nextPos;
|
|
1196
|
+
}
|
|
1197
|
+
return false;
|
|
1198
|
+
}
|
|
1199
|
+
function getObjectSchemaPropertyNames(schema) {
|
|
1200
|
+
if (!schema || typeof schema !== "object") {
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
const schemaObject = schema;
|
|
1204
|
+
const typeValue = schemaObject.type;
|
|
1205
|
+
if (typeValue != null) {
|
|
1206
|
+
const isObjectType = typeValue === "object" || Array.isArray(typeValue) && typeValue.includes("object");
|
|
1207
|
+
if (!isObjectType) {
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (!schemaObject.properties || typeof schemaObject.properties !== "object") {
|
|
1212
|
+
return /* @__PURE__ */ new Set();
|
|
1213
|
+
}
|
|
1214
|
+
return new Set(
|
|
1215
|
+
Object.keys(schemaObject.properties)
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
function schemaAllowsArrayType(schema) {
|
|
1219
|
+
if (!schema || typeof schema !== "object") {
|
|
1220
|
+
return false;
|
|
1221
|
+
}
|
|
1222
|
+
const schemaRecord = schema;
|
|
1223
|
+
const typeValue = schemaRecord.type;
|
|
1224
|
+
if (typeValue === "array") {
|
|
1225
|
+
return true;
|
|
1226
|
+
}
|
|
1227
|
+
if (Array.isArray(typeValue) && typeValue.includes("array")) {
|
|
1228
|
+
return true;
|
|
1229
|
+
}
|
|
1230
|
+
const unions = [schemaRecord.anyOf, schemaRecord.oneOf, schemaRecord.allOf];
|
|
1231
|
+
for (const union of unions) {
|
|
1232
|
+
if (!Array.isArray(union)) {
|
|
1233
|
+
continue;
|
|
1234
|
+
}
|
|
1235
|
+
if (union.some((entry) => schemaAllowsArrayType(entry))) {
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
function getSchemaObjectProperty(schema, propertyName) {
|
|
1242
|
+
if (!schema || typeof schema !== "object") {
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
const schemaObject = schema;
|
|
1246
|
+
const properties = schemaObject.properties;
|
|
1247
|
+
if (!properties || typeof properties !== "object") {
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
const property = properties[propertyName];
|
|
1251
|
+
if (!property) {
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
return property;
|
|
1255
|
+
}
|
|
1256
|
+
function isStableXmlProgressCandidate(options) {
|
|
1257
|
+
const { candidate, parsed, toolSchema } = options;
|
|
1258
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
const structure = analyzeXmlFragmentForProgress(candidate);
|
|
1262
|
+
if (!structure) {
|
|
1263
|
+
return false;
|
|
1264
|
+
}
|
|
1265
|
+
const schemaProperties = getObjectSchemaPropertyNames(toolSchema);
|
|
1266
|
+
if (!schemaProperties || schemaProperties.size === 0) {
|
|
1267
|
+
return false;
|
|
1268
|
+
}
|
|
1269
|
+
const parsedObject = parsed;
|
|
1270
|
+
const uniqueTopLevelTags = new Set(structure.topLevelTagNames);
|
|
1271
|
+
for (const tagName of uniqueTopLevelTags) {
|
|
1272
|
+
if (!schemaProperties.has(tagName)) {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
const schemaProperty = getSchemaObjectProperty(toolSchema, tagName);
|
|
1276
|
+
if (schemaProperty && schemaAllowsArrayType(schemaProperty) && !Array.isArray(parsedObject[tagName])) {
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
if (structure.topLevelTagNames.length === 1) {
|
|
1281
|
+
const onlyTopLevelTag = structure.topLevelTagNames[0];
|
|
1282
|
+
if (!schemaProperties || schemaProperties.size === 0 || !schemaProperties.has(onlyTopLevelTag)) {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return true;
|
|
1287
|
+
}
|
|
1288
|
+
function parseXmlContentForStreamProgress({
|
|
1289
|
+
toolContent,
|
|
1290
|
+
toolSchema,
|
|
1291
|
+
parseOptions
|
|
1292
|
+
}) {
|
|
1293
|
+
const tryParse = (content) => {
|
|
1294
|
+
try {
|
|
1295
|
+
return parse2(content, toolSchema, {
|
|
1296
|
+
...parseOptions != null ? parseOptions : {},
|
|
1297
|
+
repair: false,
|
|
1298
|
+
onError: void 0
|
|
1299
|
+
});
|
|
1300
|
+
} catch (e) {
|
|
1301
|
+
return null;
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
const strictFull = tryParse(toolContent);
|
|
1305
|
+
if (strictFull !== null && isStableXmlProgressCandidate({
|
|
1306
|
+
candidate: toolContent,
|
|
1307
|
+
parsed: strictFull,
|
|
1308
|
+
toolSchema
|
|
1309
|
+
})) {
|
|
1310
|
+
return JSON.stringify(strictFull);
|
|
1311
|
+
}
|
|
1312
|
+
let searchEnd = toolContent.length;
|
|
1313
|
+
while (searchEnd > 0) {
|
|
1314
|
+
const gtIndex = toolContent.lastIndexOf(">", searchEnd - 1);
|
|
1315
|
+
if (gtIndex === -1) {
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
const candidate = toolContent.slice(0, gtIndex + 1);
|
|
1319
|
+
if (!analyzeXmlFragmentForProgress(candidate)) {
|
|
1320
|
+
searchEnd = gtIndex;
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1323
|
+
const parsedCandidate = tryParse(candidate);
|
|
1324
|
+
if (parsedCandidate !== null && isStableXmlProgressCandidate({
|
|
1325
|
+
candidate,
|
|
1326
|
+
parsed: parsedCandidate,
|
|
1327
|
+
toolSchema
|
|
1328
|
+
})) {
|
|
1329
|
+
return JSON.stringify(parsedCandidate);
|
|
1330
|
+
}
|
|
1331
|
+
searchEnd = gtIndex;
|
|
1332
|
+
}
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
555
1335
|
function handleStreamingToolCallEnd(params) {
|
|
556
1336
|
var _a, _b;
|
|
557
1337
|
const {
|
|
@@ -571,19 +1351,37 @@ function handleStreamingToolCallEnd(params) {
|
|
|
571
1351
|
flushText(ctrl);
|
|
572
1352
|
try {
|
|
573
1353
|
const parsedResult = parse2(toolContent, toolSchema, parseConfig);
|
|
1354
|
+
const finalInput = JSON.stringify(parsedResult);
|
|
1355
|
+
emitFinalRemainder({
|
|
1356
|
+
controller: ctrl,
|
|
1357
|
+
id: currentToolCall.toolCallId,
|
|
1358
|
+
state: currentToolCall,
|
|
1359
|
+
finalFullJson: finalInput,
|
|
1360
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
1361
|
+
});
|
|
1362
|
+
ctrl.enqueue({
|
|
1363
|
+
type: "tool-input-end",
|
|
1364
|
+
id: currentToolCall.toolCallId
|
|
1365
|
+
});
|
|
574
1366
|
ctrl.enqueue({
|
|
575
1367
|
type: "tool-call",
|
|
576
|
-
toolCallId:
|
|
1368
|
+
toolCallId: currentToolCall.toolCallId,
|
|
577
1369
|
toolName: currentToolCall.name,
|
|
578
|
-
input:
|
|
1370
|
+
input: finalInput
|
|
579
1371
|
});
|
|
580
1372
|
} catch (error) {
|
|
1373
|
+
ctrl.enqueue({
|
|
1374
|
+
type: "tool-input-end",
|
|
1375
|
+
id: currentToolCall.toolCallId
|
|
1376
|
+
});
|
|
581
1377
|
const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
|
|
582
1378
|
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
|
|
583
1379
|
toolCall: original,
|
|
584
1380
|
error
|
|
585
1381
|
});
|
|
586
|
-
|
|
1382
|
+
if (shouldEmitRawToolCallTextOnError2(options)) {
|
|
1383
|
+
flushText(ctrl, original);
|
|
1384
|
+
}
|
|
587
1385
|
}
|
|
588
1386
|
}
|
|
589
1387
|
function findClosingTagEndFlexible(text, contentStart, toolName) {
|
|
@@ -799,6 +1597,102 @@ function findToolCalls(text, toolNames) {
|
|
|
799
1597
|
}
|
|
800
1598
|
return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
|
|
801
1599
|
}
|
|
1600
|
+
function handleSpecialToken(depth) {
|
|
1601
|
+
return { depth, lastCompleteEnd: -1, shouldBreak: false };
|
|
1602
|
+
}
|
|
1603
|
+
function handleOpenToken(token, depth, lastCompleteEnd) {
|
|
1604
|
+
if (token.selfClosing) {
|
|
1605
|
+
return {
|
|
1606
|
+
depth,
|
|
1607
|
+
lastCompleteEnd: depth === 0 ? token.nextPos : lastCompleteEnd,
|
|
1608
|
+
shouldBreak: false
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
return { depth: depth + 1, lastCompleteEnd, shouldBreak: false };
|
|
1612
|
+
}
|
|
1613
|
+
function handleCloseToken(token, depth) {
|
|
1614
|
+
if (depth <= 0) {
|
|
1615
|
+
return { depth, lastCompleteEnd: -1, shouldBreak: true };
|
|
1616
|
+
}
|
|
1617
|
+
const newDepth = depth - 1;
|
|
1618
|
+
return {
|
|
1619
|
+
depth: newDepth,
|
|
1620
|
+
lastCompleteEnd: newDepth === 0 ? token.nextPos : -1,
|
|
1621
|
+
shouldBreak: false
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
function findLinePrefixedXmlBodyEnd(text, bodyStartIndex) {
|
|
1625
|
+
let cursor = bodyStartIndex;
|
|
1626
|
+
let depth = 0;
|
|
1627
|
+
let lastCompleteEnd = -1;
|
|
1628
|
+
while (cursor < text.length) {
|
|
1629
|
+
if (depth === 0) {
|
|
1630
|
+
cursor = consumeWhitespace(text, cursor);
|
|
1631
|
+
if (cursor >= text.length || text.charAt(cursor) !== "<") {
|
|
1632
|
+
break;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
const token = nextTagToken(text, cursor);
|
|
1636
|
+
if (token.kind === "eof") {
|
|
1637
|
+
break;
|
|
1638
|
+
}
|
|
1639
|
+
let result;
|
|
1640
|
+
if (token.kind === "special") {
|
|
1641
|
+
result = handleSpecialToken(depth);
|
|
1642
|
+
} else if (token.kind === "open") {
|
|
1643
|
+
result = handleOpenToken(token, depth, lastCompleteEnd);
|
|
1644
|
+
} else {
|
|
1645
|
+
result = handleCloseToken(token, depth);
|
|
1646
|
+
}
|
|
1647
|
+
depth = result.depth;
|
|
1648
|
+
if (result.lastCompleteEnd !== -1) {
|
|
1649
|
+
lastCompleteEnd = result.lastCompleteEnd;
|
|
1650
|
+
}
|
|
1651
|
+
if (result.shouldBreak) {
|
|
1652
|
+
break;
|
|
1653
|
+
}
|
|
1654
|
+
cursor = token.nextPos;
|
|
1655
|
+
}
|
|
1656
|
+
return lastCompleteEnd;
|
|
1657
|
+
}
|
|
1658
|
+
function findLinePrefixedToolCall(text, toolNames) {
|
|
1659
|
+
var _a;
|
|
1660
|
+
let best = null;
|
|
1661
|
+
for (const toolName of toolNames) {
|
|
1662
|
+
const linePattern = new RegExp(
|
|
1663
|
+
`(^|\\n)[\\t ]*${escapeRegExp(toolName)}[\\t ]*:?[\\t ]*(?:\\r?\\n|$)`,
|
|
1664
|
+
"g"
|
|
1665
|
+
);
|
|
1666
|
+
let match = linePattern.exec(text);
|
|
1667
|
+
while (match !== null) {
|
|
1668
|
+
const prefix = (_a = match[1]) != null ? _a : "";
|
|
1669
|
+
const startIndex = match.index + prefix.length;
|
|
1670
|
+
const contentStart = consumeWhitespace(text, linePattern.lastIndex);
|
|
1671
|
+
if (contentStart >= text.length || text.charAt(contentStart) !== "<") {
|
|
1672
|
+
match = linePattern.exec(text);
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
const contentEnd = findLinePrefixedXmlBodyEnd(text, contentStart);
|
|
1676
|
+
if (contentEnd === -1 || contentEnd <= contentStart) {
|
|
1677
|
+
match = linePattern.exec(text);
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
const content = text.slice(contentStart, contentEnd);
|
|
1681
|
+
const candidate = {
|
|
1682
|
+
toolName,
|
|
1683
|
+
startIndex,
|
|
1684
|
+
endIndex: contentEnd,
|
|
1685
|
+
content,
|
|
1686
|
+
segment: text.slice(startIndex, contentEnd)
|
|
1687
|
+
};
|
|
1688
|
+
if (best === null || candidate.startIndex < best.startIndex) {
|
|
1689
|
+
best = candidate;
|
|
1690
|
+
}
|
|
1691
|
+
break;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return best;
|
|
1695
|
+
}
|
|
802
1696
|
function findEarliestToolTag(buffer, toolNames) {
|
|
803
1697
|
var _a, _b;
|
|
804
1698
|
let bestIndex = -1;
|
|
@@ -909,38 +1803,6 @@ function findPotentialToolTagStart(buffer, toolNames) {
|
|
|
909
1803
|
}
|
|
910
1804
|
return -1;
|
|
911
1805
|
}
|
|
912
|
-
function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
913
|
-
return (controller, text) => {
|
|
914
|
-
const content = text;
|
|
915
|
-
if (content) {
|
|
916
|
-
if (!getCurrentTextId()) {
|
|
917
|
-
const newId = generateId();
|
|
918
|
-
setCurrentTextId(newId);
|
|
919
|
-
controller.enqueue({
|
|
920
|
-
type: "text-start",
|
|
921
|
-
id: newId
|
|
922
|
-
});
|
|
923
|
-
setHasEmittedTextStart(true);
|
|
924
|
-
}
|
|
925
|
-
controller.enqueue({
|
|
926
|
-
type: "text-delta",
|
|
927
|
-
id: getCurrentTextId(),
|
|
928
|
-
delta: content
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
const currentTextId = getCurrentTextId();
|
|
932
|
-
if (currentTextId && !text) {
|
|
933
|
-
if (getHasEmittedTextStart()) {
|
|
934
|
-
controller.enqueue({
|
|
935
|
-
type: "text-end",
|
|
936
|
-
id: currentTextId
|
|
937
|
-
});
|
|
938
|
-
setHasEmittedTextStart(false);
|
|
939
|
-
}
|
|
940
|
-
setCurrentTextId(null);
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
1806
|
function processToolCallInBuffer(params) {
|
|
945
1807
|
const {
|
|
946
1808
|
buffer,
|
|
@@ -950,18 +1812,21 @@ function processToolCallInBuffer(params) {
|
|
|
950
1812
|
controller,
|
|
951
1813
|
flushText,
|
|
952
1814
|
setBuffer,
|
|
953
|
-
parseOptions
|
|
1815
|
+
parseOptions,
|
|
1816
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
954
1817
|
} = params;
|
|
955
1818
|
const endTagPattern = new RegExp(
|
|
956
1819
|
`</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
|
|
957
1820
|
);
|
|
958
1821
|
const endMatch = endTagPattern.exec(buffer);
|
|
959
1822
|
if (!endMatch || endMatch.index === void 0) {
|
|
1823
|
+
emitToolInputProgress2(controller, currentToolCall, buffer);
|
|
960
1824
|
return { buffer, currentToolCall, shouldBreak: true };
|
|
961
1825
|
}
|
|
962
1826
|
const endIdx = endMatch.index;
|
|
963
1827
|
const endPos = endIdx + endMatch[0].length;
|
|
964
1828
|
const content = buffer.substring(0, endIdx);
|
|
1829
|
+
emitToolInputProgress2(controller, currentToolCall, content);
|
|
965
1830
|
const remainder = buffer.substring(endPos);
|
|
966
1831
|
setBuffer(remainder);
|
|
967
1832
|
handleStreamingToolCallEnd({
|
|
@@ -988,7 +1853,8 @@ function processNoToolCallInBuffer(params) {
|
|
|
988
1853
|
tools,
|
|
989
1854
|
options,
|
|
990
1855
|
parseOptions,
|
|
991
|
-
setBuffer
|
|
1856
|
+
setBuffer,
|
|
1857
|
+
emitToolInputStart
|
|
992
1858
|
} = params;
|
|
993
1859
|
const {
|
|
994
1860
|
index: earliestStartTagIndex,
|
|
@@ -1018,9 +1884,10 @@ function processNoToolCallInBuffer(params) {
|
|
|
1018
1884
|
if (selfClosing) {
|
|
1019
1885
|
const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
|
|
1020
1886
|
setBuffer(newBuffer2);
|
|
1887
|
+
const currentToolCall = emitToolInputStart(controller, earliestToolName);
|
|
1021
1888
|
handleStreamingToolCallEnd({
|
|
1022
1889
|
toolContent: "",
|
|
1023
|
-
currentToolCall
|
|
1890
|
+
currentToolCall,
|
|
1024
1891
|
tools,
|
|
1025
1892
|
options,
|
|
1026
1893
|
ctrl: controller,
|
|
@@ -1039,12 +1906,12 @@ function processNoToolCallInBuffer(params) {
|
|
|
1039
1906
|
setBuffer(newBuffer);
|
|
1040
1907
|
return {
|
|
1041
1908
|
buffer: newBuffer,
|
|
1042
|
-
currentToolCall:
|
|
1909
|
+
currentToolCall: emitToolInputStart(controller, earliestToolName),
|
|
1043
1910
|
shouldBreak: false,
|
|
1044
1911
|
shouldContinue: true
|
|
1045
1912
|
};
|
|
1046
1913
|
}
|
|
1047
|
-
function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions) {
|
|
1914
|
+
function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions, emitToolInputProgress2, emitToolInputStart) {
|
|
1048
1915
|
return (controller) => {
|
|
1049
1916
|
while (true) {
|
|
1050
1917
|
const currentToolCall = getCurrentToolCall();
|
|
@@ -1057,7 +1924,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1057
1924
|
controller,
|
|
1058
1925
|
flushText,
|
|
1059
1926
|
setBuffer,
|
|
1060
|
-
parseOptions
|
|
1927
|
+
parseOptions,
|
|
1928
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
1061
1929
|
});
|
|
1062
1930
|
setBuffer(result.buffer);
|
|
1063
1931
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1073,7 +1941,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1073
1941
|
tools,
|
|
1074
1942
|
options,
|
|
1075
1943
|
parseOptions,
|
|
1076
|
-
setBuffer
|
|
1944
|
+
setBuffer,
|
|
1945
|
+
emitToolInputStart
|
|
1077
1946
|
});
|
|
1078
1947
|
setBuffer(result.buffer);
|
|
1079
1948
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1088,6 +1957,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1088
1957
|
}
|
|
1089
1958
|
};
|
|
1090
1959
|
}
|
|
1960
|
+
function findToolCallsWithFallbacks(text, toolNames) {
|
|
1961
|
+
let parseText = text;
|
|
1962
|
+
let toolCalls = findToolCalls(parseText, toolNames);
|
|
1963
|
+
if (toolCalls.length === 0) {
|
|
1964
|
+
const fallbackToolCall = findLinePrefixedToolCall(parseText, toolNames);
|
|
1965
|
+
if (fallbackToolCall !== null) {
|
|
1966
|
+
toolCalls.push(fallbackToolCall);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
if (toolCalls.length === 0) {
|
|
1970
|
+
const repaired = tryRepairXmlSelfClosingRootWithBody(parseText, toolNames);
|
|
1971
|
+
if (repaired) {
|
|
1972
|
+
const repairedCalls = findToolCalls(repaired, toolNames);
|
|
1973
|
+
if (repairedCalls.length > 0) {
|
|
1974
|
+
parseText = repaired;
|
|
1975
|
+
toolCalls = repairedCalls;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return { parseText, toolCalls };
|
|
1980
|
+
}
|
|
1091
1981
|
var xmlProtocol = (protocolOptions) => {
|
|
1092
1982
|
var _a;
|
|
1093
1983
|
const parseOptions = {
|
|
@@ -1121,28 +2011,31 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1121
2011
|
}
|
|
1122
2012
|
const processedElements = [];
|
|
1123
2013
|
let currentIndex = 0;
|
|
1124
|
-
const toolCalls =
|
|
2014
|
+
const { parseText, toolCalls } = findToolCallsWithFallbacks(
|
|
2015
|
+
text,
|
|
2016
|
+
toolNames
|
|
2017
|
+
);
|
|
1125
2018
|
for (const tc of toolCalls) {
|
|
1126
2019
|
if (tc.startIndex > currentIndex) {
|
|
1127
2020
|
processedElements.push({
|
|
1128
2021
|
type: "text",
|
|
1129
|
-
text:
|
|
2022
|
+
text: parseText.substring(currentIndex, tc.startIndex)
|
|
1130
2023
|
});
|
|
1131
2024
|
}
|
|
1132
2025
|
processToolCall({
|
|
1133
2026
|
toolCall: tc,
|
|
1134
2027
|
tools,
|
|
1135
2028
|
options,
|
|
1136
|
-
text,
|
|
2029
|
+
text: parseText,
|
|
1137
2030
|
processedElements,
|
|
1138
2031
|
parseOptions
|
|
1139
2032
|
});
|
|
1140
2033
|
currentIndex = tc.endIndex;
|
|
1141
2034
|
}
|
|
1142
|
-
if (currentIndex <
|
|
2035
|
+
if (currentIndex < parseText.length) {
|
|
1143
2036
|
processedElements.push({
|
|
1144
2037
|
type: "text",
|
|
1145
|
-
text:
|
|
2038
|
+
text: parseText.substring(currentIndex)
|
|
1146
2039
|
});
|
|
1147
2040
|
}
|
|
1148
2041
|
return processedElements;
|
|
@@ -1163,6 +2056,118 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1163
2056
|
hasEmittedTextStart = value;
|
|
1164
2057
|
}
|
|
1165
2058
|
);
|
|
2059
|
+
const emitToolInputStart = (controller, toolName) => {
|
|
2060
|
+
flushText(controller);
|
|
2061
|
+
const next = {
|
|
2062
|
+
name: toolName,
|
|
2063
|
+
toolCallId: generateToolCallId(),
|
|
2064
|
+
emittedInput: "",
|
|
2065
|
+
lastProgressGtIndex: null,
|
|
2066
|
+
lastProgressFullInput: null
|
|
2067
|
+
};
|
|
2068
|
+
controller.enqueue({
|
|
2069
|
+
type: "tool-input-start",
|
|
2070
|
+
id: next.toolCallId,
|
|
2071
|
+
toolName
|
|
2072
|
+
});
|
|
2073
|
+
return next;
|
|
2074
|
+
};
|
|
2075
|
+
const emitToolInputProgress2 = (controller, toolCall, toolContent) => {
|
|
2076
|
+
const progressGtIndex = toolContent.lastIndexOf(">");
|
|
2077
|
+
if (toolCall.lastProgressGtIndex === progressGtIndex) {
|
|
2078
|
+
const cached = toolCall.lastProgressFullInput;
|
|
2079
|
+
if (cached == null) {
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (cached === "{}" && toolContent.trim().length === 0) {
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
const prefixCandidate2 = toIncompleteJsonPrefix(cached);
|
|
2086
|
+
emitPrefixDelta({
|
|
2087
|
+
controller,
|
|
2088
|
+
id: toolCall.toolCallId,
|
|
2089
|
+
state: toolCall,
|
|
2090
|
+
candidate: prefixCandidate2
|
|
2091
|
+
});
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
const toolSchema = getToolSchema(tools, toolCall.name);
|
|
2095
|
+
const fullInput = parseXmlContentForStreamProgress({
|
|
2096
|
+
toolContent,
|
|
2097
|
+
toolSchema,
|
|
2098
|
+
parseOptions
|
|
2099
|
+
});
|
|
2100
|
+
toolCall.lastProgressGtIndex = progressGtIndex;
|
|
2101
|
+
toolCall.lastProgressFullInput = fullInput;
|
|
2102
|
+
if (fullInput == null) {
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
if (fullInput === "{}" && toolContent.trim().length === 0) {
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
const prefixCandidate = toIncompleteJsonPrefix(fullInput);
|
|
2109
|
+
emitPrefixDelta({
|
|
2110
|
+
controller,
|
|
2111
|
+
id: toolCall.toolCallId,
|
|
2112
|
+
state: toolCall,
|
|
2113
|
+
candidate: prefixCandidate
|
|
2114
|
+
});
|
|
2115
|
+
};
|
|
2116
|
+
const finalizeUnclosedToolCall = (controller) => {
|
|
2117
|
+
var _a2, _b;
|
|
2118
|
+
if (!currentToolCall) {
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
emitToolInputProgress2(controller, currentToolCall, buffer);
|
|
2122
|
+
const parseConfig = {
|
|
2123
|
+
...parseOptions,
|
|
2124
|
+
onError: (_a2 = options == null ? void 0 : options.onError) != null ? _a2 : parseOptions == null ? void 0 : parseOptions.onError
|
|
2125
|
+
};
|
|
2126
|
+
const toolSchema = getToolSchema(tools, currentToolCall.name);
|
|
2127
|
+
flushText(controller);
|
|
2128
|
+
try {
|
|
2129
|
+
if (hasNonWhitespaceTopLevelText(buffer)) {
|
|
2130
|
+
throw new Error(
|
|
2131
|
+
"Cannot reconcile unclosed XML tool call with top-level plain text."
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
const parsedResult = parse2(buffer, toolSchema, parseConfig);
|
|
2135
|
+
const finalInput = JSON.stringify(parsedResult);
|
|
2136
|
+
emitFinalRemainder({
|
|
2137
|
+
controller,
|
|
2138
|
+
id: currentToolCall.toolCallId,
|
|
2139
|
+
state: currentToolCall,
|
|
2140
|
+
finalFullJson: finalInput,
|
|
2141
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2142
|
+
});
|
|
2143
|
+
controller.enqueue({
|
|
2144
|
+
type: "tool-input-end",
|
|
2145
|
+
id: currentToolCall.toolCallId
|
|
2146
|
+
});
|
|
2147
|
+
controller.enqueue({
|
|
2148
|
+
type: "tool-call",
|
|
2149
|
+
toolCallId: currentToolCall.toolCallId,
|
|
2150
|
+
toolName: currentToolCall.name,
|
|
2151
|
+
input: finalInput
|
|
2152
|
+
});
|
|
2153
|
+
} catch (error) {
|
|
2154
|
+
controller.enqueue({
|
|
2155
|
+
type: "tool-input-end",
|
|
2156
|
+
id: currentToolCall.toolCallId
|
|
2157
|
+
});
|
|
2158
|
+
const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
|
|
2159
|
+
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
|
|
2160
|
+
options,
|
|
2161
|
+
"Could not complete streaming XML tool call at finish.",
|
|
2162
|
+
{ toolCall: unfinishedContent, error }
|
|
2163
|
+
);
|
|
2164
|
+
if (shouldEmitRawToolCallTextOnError2(options)) {
|
|
2165
|
+
flushText(controller, unfinishedContent);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
buffer = "";
|
|
2169
|
+
currentToolCall = null;
|
|
2170
|
+
};
|
|
1166
2171
|
const processBuffer = createProcessBufferHandler(
|
|
1167
2172
|
() => buffer,
|
|
1168
2173
|
(newBuffer) => {
|
|
@@ -1176,13 +2181,28 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1176
2181
|
options,
|
|
1177
2182
|
toolNames,
|
|
1178
2183
|
flushText,
|
|
1179
|
-
parseOptions
|
|
2184
|
+
parseOptions,
|
|
2185
|
+
emitToolInputProgress2,
|
|
2186
|
+
emitToolInputStart
|
|
1180
2187
|
);
|
|
1181
2188
|
return new TransformStream({
|
|
2189
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Stateful stream parsing requires branching over chunk lifecycle and parser states.
|
|
1182
2190
|
transform(chunk, controller) {
|
|
1183
2191
|
var _a2;
|
|
2192
|
+
if (chunk.type === "finish") {
|
|
2193
|
+
if (currentToolCall) {
|
|
2194
|
+
finalizeUnclosedToolCall(controller);
|
|
2195
|
+
} else if (buffer) {
|
|
2196
|
+
flushText(controller, buffer);
|
|
2197
|
+
buffer = "";
|
|
2198
|
+
}
|
|
2199
|
+
flushText(controller);
|
|
2200
|
+
controller.enqueue(chunk);
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
1184
2203
|
if (chunk.type !== "text-delta") {
|
|
1185
|
-
if (
|
|
2204
|
+
if (currentToolCall) {
|
|
2205
|
+
} else if (buffer) {
|
|
1186
2206
|
flushText(controller, buffer);
|
|
1187
2207
|
buffer = "";
|
|
1188
2208
|
}
|
|
@@ -1195,10 +2215,7 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1195
2215
|
},
|
|
1196
2216
|
flush(controller) {
|
|
1197
2217
|
if (currentToolCall) {
|
|
1198
|
-
|
|
1199
|
-
flushText(controller, unfinishedContent);
|
|
1200
|
-
buffer = "";
|
|
1201
|
-
currentToolCall = null;
|
|
2218
|
+
finalizeUnclosedToolCall(controller);
|
|
1202
2219
|
} else if (buffer) {
|
|
1203
2220
|
flushText(controller, buffer);
|
|
1204
2221
|
buffer = "";
|
|
@@ -1226,7 +2243,205 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1226
2243
|
|
|
1227
2244
|
// src/core/protocols/yaml-protocol.ts
|
|
1228
2245
|
import YAML from "yaml";
|
|
2246
|
+
function shouldEmitRawToolCallTextOnError3(options) {
|
|
2247
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
2248
|
+
}
|
|
2249
|
+
var selfClosingTagCache2 = /* @__PURE__ */ new Map();
|
|
2250
|
+
function getSelfClosingTagPattern2(toolName) {
|
|
2251
|
+
let pattern = selfClosingTagCache2.get(toolName);
|
|
2252
|
+
if (!pattern) {
|
|
2253
|
+
pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
|
|
2254
|
+
selfClosingTagCache2.set(toolName, pattern);
|
|
2255
|
+
}
|
|
2256
|
+
return pattern;
|
|
2257
|
+
}
|
|
1229
2258
|
var LEADING_WHITESPACE_RE = /^(\s*)/;
|
|
2259
|
+
var INCOMPLETE_MAPPING_TAIL_RE = /^[^:[\]{}-][^:]*:\s*$/;
|
|
2260
|
+
var INCOMPLETE_SEQUENCE_TAIL_RE = /^-\s*$/;
|
|
2261
|
+
var BLOCK_SCALAR_KEY_RE = /:\s*[|>][-+0-9]*\s*$/;
|
|
2262
|
+
var PLAIN_MAPPING_VALUE_RE = /^[^:[\]{}-][^:]*:\s*(.+)$/;
|
|
2263
|
+
var PLAIN_SEQUENCE_VALUE_RE = /^-\s+(.+)$/;
|
|
2264
|
+
function normalizeYamlContent(yamlContent) {
|
|
2265
|
+
let normalized = yamlContent;
|
|
2266
|
+
if (normalized.startsWith("\n")) {
|
|
2267
|
+
normalized = normalized.slice(1);
|
|
2268
|
+
}
|
|
2269
|
+
const lines = normalized.split("\n");
|
|
2270
|
+
const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
|
|
2271
|
+
if (nonEmptyLines.length === 0) {
|
|
2272
|
+
return { normalized: "", nonEmptyLines };
|
|
2273
|
+
}
|
|
2274
|
+
const minIndent = Math.min(
|
|
2275
|
+
...nonEmptyLines.map((line) => {
|
|
2276
|
+
const match = line.match(LEADING_WHITESPACE_RE);
|
|
2277
|
+
return match ? match[1].length : 0;
|
|
2278
|
+
})
|
|
2279
|
+
);
|
|
2280
|
+
if (minIndent > 0) {
|
|
2281
|
+
normalized = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
2282
|
+
}
|
|
2283
|
+
return { normalized, nonEmptyLines };
|
|
2284
|
+
}
|
|
2285
|
+
function parseYamlDocumentAsMapping(normalized) {
|
|
2286
|
+
try {
|
|
2287
|
+
const doc = YAML.parseDocument(normalized);
|
|
2288
|
+
const errors = doc.errors.map((e) => e.message);
|
|
2289
|
+
const result = doc.toJSON();
|
|
2290
|
+
if (result === null) {
|
|
2291
|
+
return { value: {}, errors };
|
|
2292
|
+
}
|
|
2293
|
+
if (typeof result !== "object" || Array.isArray(result)) {
|
|
2294
|
+
return { value: null, errors };
|
|
2295
|
+
}
|
|
2296
|
+
return { value: result, errors };
|
|
2297
|
+
} catch (error) {
|
|
2298
|
+
return {
|
|
2299
|
+
value: null,
|
|
2300
|
+
errors: [
|
|
2301
|
+
error instanceof Error ? error.message : "Unknown YAML parsing error"
|
|
2302
|
+
]
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
function getLastMeaningfulLineInfo(input) {
|
|
2307
|
+
var _a;
|
|
2308
|
+
const lines = input.split("\n");
|
|
2309
|
+
let index = lines.length - 1;
|
|
2310
|
+
while (index >= 0) {
|
|
2311
|
+
const raw = (_a = lines[index]) != null ? _a : "";
|
|
2312
|
+
const trimmed = raw.trim();
|
|
2313
|
+
if (trimmed.length > 0 && !trimmed.startsWith("#")) {
|
|
2314
|
+
return {
|
|
2315
|
+
index,
|
|
2316
|
+
raw,
|
|
2317
|
+
trimmed,
|
|
2318
|
+
indent: raw.length - raw.trimStart().length
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
index -= 1;
|
|
2322
|
+
}
|
|
2323
|
+
return null;
|
|
2324
|
+
}
|
|
2325
|
+
function dropLastMeaningfulLine(input) {
|
|
2326
|
+
const lineInfo = getLastMeaningfulLineInfo(input);
|
|
2327
|
+
if (!lineInfo) {
|
|
2328
|
+
return null;
|
|
2329
|
+
}
|
|
2330
|
+
return input.split("\n").slice(0, lineInfo.index).join("\n").trimEnd();
|
|
2331
|
+
}
|
|
2332
|
+
function hasIncompleteMappingTail(normalized) {
|
|
2333
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2334
|
+
if (!lineInfo) {
|
|
2335
|
+
return false;
|
|
2336
|
+
}
|
|
2337
|
+
return INCOMPLETE_MAPPING_TAIL_RE.test(lineInfo.trimmed);
|
|
2338
|
+
}
|
|
2339
|
+
function hasIncompleteSequenceTail(normalized) {
|
|
2340
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2341
|
+
if (!lineInfo) {
|
|
2342
|
+
return false;
|
|
2343
|
+
}
|
|
2344
|
+
return INCOMPLETE_SEQUENCE_TAIL_RE.test(lineInfo.trimmed);
|
|
2345
|
+
}
|
|
2346
|
+
function hasSplitNestedKeyTail(normalized) {
|
|
2347
|
+
var _a;
|
|
2348
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2349
|
+
if (!lineInfo) {
|
|
2350
|
+
return false;
|
|
2351
|
+
}
|
|
2352
|
+
const { trimmed, indent, index } = lineInfo;
|
|
2353
|
+
if (indent === 0) {
|
|
2354
|
+
return false;
|
|
2355
|
+
}
|
|
2356
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("-") || trimmed.includes(":")) {
|
|
2357
|
+
return false;
|
|
2358
|
+
}
|
|
2359
|
+
const lines = normalized.split("\n");
|
|
2360
|
+
let parentIndex = index - 1;
|
|
2361
|
+
while (parentIndex >= 0) {
|
|
2362
|
+
const parentRaw = (_a = lines[parentIndex]) != null ? _a : "";
|
|
2363
|
+
const parentTrimmed = parentRaw.trim();
|
|
2364
|
+
if (parentTrimmed.length === 0 || parentTrimmed.startsWith("#")) {
|
|
2365
|
+
parentIndex -= 1;
|
|
2366
|
+
continue;
|
|
2367
|
+
}
|
|
2368
|
+
const parentIndent = parentRaw.length - parentRaw.trimStart().length;
|
|
2369
|
+
if (parentIndent >= indent) {
|
|
2370
|
+
parentIndex -= 1;
|
|
2371
|
+
continue;
|
|
2372
|
+
}
|
|
2373
|
+
if (!parentTrimmed.endsWith(":")) {
|
|
2374
|
+
return false;
|
|
2375
|
+
}
|
|
2376
|
+
if (BLOCK_SCALAR_KEY_RE.test(parentTrimmed)) {
|
|
2377
|
+
return false;
|
|
2378
|
+
}
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
return false;
|
|
2382
|
+
}
|
|
2383
|
+
function extractTrailingPlainScalarValue(line) {
|
|
2384
|
+
var _a;
|
|
2385
|
+
if (BLOCK_SCALAR_KEY_RE.test(line)) {
|
|
2386
|
+
return null;
|
|
2387
|
+
}
|
|
2388
|
+
const mappingMatch = line.match(PLAIN_MAPPING_VALUE_RE);
|
|
2389
|
+
const sequenceMatch = line.match(PLAIN_SEQUENCE_VALUE_RE);
|
|
2390
|
+
const value = (_a = mappingMatch == null ? void 0 : mappingMatch[1]) != null ? _a : sequenceMatch == null ? void 0 : sequenceMatch[1];
|
|
2391
|
+
if (!value) {
|
|
2392
|
+
return null;
|
|
2393
|
+
}
|
|
2394
|
+
const trimmedValue = value.trim();
|
|
2395
|
+
if (trimmedValue.length === 0) {
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
if (trimmedValue.startsWith('"') || trimmedValue.startsWith("'")) {
|
|
2399
|
+
return null;
|
|
2400
|
+
}
|
|
2401
|
+
if (trimmedValue.startsWith("{") || trimmedValue.startsWith("[") || trimmedValue.startsWith("|") || trimmedValue.startsWith(">")) {
|
|
2402
|
+
return null;
|
|
2403
|
+
}
|
|
2404
|
+
return trimmedValue;
|
|
2405
|
+
}
|
|
2406
|
+
function hasUnterminatedPlainScalarTail(normalized) {
|
|
2407
|
+
if (normalized.endsWith("\n")) {
|
|
2408
|
+
return false;
|
|
2409
|
+
}
|
|
2410
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2411
|
+
if (!lineInfo) {
|
|
2412
|
+
return false;
|
|
2413
|
+
}
|
|
2414
|
+
return extractTrailingPlainScalarValue(lineInfo.trimmed) != null;
|
|
2415
|
+
}
|
|
2416
|
+
function hasUnstableProgressTail(normalized) {
|
|
2417
|
+
return hasIncompleteMappingTail(normalized) || hasIncompleteSequenceTail(normalized) || hasSplitNestedKeyTail(normalized) || hasUnterminatedPlainScalarTail(normalized);
|
|
2418
|
+
}
|
|
2419
|
+
function trimTrailingNewlineInUnknown(value) {
|
|
2420
|
+
if (typeof value === "string") {
|
|
2421
|
+
if (value.endsWith("\n")) {
|
|
2422
|
+
return value.slice(0, -1);
|
|
2423
|
+
}
|
|
2424
|
+
return value;
|
|
2425
|
+
}
|
|
2426
|
+
if (Array.isArray(value)) {
|
|
2427
|
+
return value.map((item) => trimTrailingNewlineInUnknown(item));
|
|
2428
|
+
}
|
|
2429
|
+
if (value && typeof value === "object") {
|
|
2430
|
+
return Object.fromEntries(
|
|
2431
|
+
Object.entries(value).map(([key, item]) => [
|
|
2432
|
+
key,
|
|
2433
|
+
trimTrailingNewlineInUnknown(item)
|
|
2434
|
+
])
|
|
2435
|
+
);
|
|
2436
|
+
}
|
|
2437
|
+
return value;
|
|
2438
|
+
}
|
|
2439
|
+
function stabilizeParsedValueForStreamProgress(value, source) {
|
|
2440
|
+
if (source.endsWith("\n")) {
|
|
2441
|
+
return value;
|
|
2442
|
+
}
|
|
2443
|
+
return trimTrailingNewlineInUnknown(value);
|
|
2444
|
+
}
|
|
1230
2445
|
function findClosingTagEnd(text, contentStart, toolName) {
|
|
1231
2446
|
let pos = contentStart;
|
|
1232
2447
|
let depth = 1;
|
|
@@ -1298,7 +2513,7 @@ function findEarliestTagPosition(openIdx, selfIdx) {
|
|
|
1298
2513
|
function collectToolCallsForName(text, toolName) {
|
|
1299
2514
|
const toolCalls = [];
|
|
1300
2515
|
let searchIndex = 0;
|
|
1301
|
-
const selfTagRegex =
|
|
2516
|
+
const selfTagRegex = getSelfClosingTagPattern2(toolName);
|
|
1302
2517
|
while (searchIndex < text.length) {
|
|
1303
2518
|
const startTag = `<${toolName}>`;
|
|
1304
2519
|
const openIdx = text.indexOf(startTag, searchIndex);
|
|
@@ -1350,47 +2565,48 @@ function findToolCalls2(text, toolNames) {
|
|
|
1350
2565
|
return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
|
|
1351
2566
|
}
|
|
1352
2567
|
function parseYamlContent(yamlContent, options) {
|
|
1353
|
-
var _a, _b
|
|
1354
|
-
|
|
1355
|
-
if (normalized.startsWith("\n")) {
|
|
1356
|
-
normalized = normalized.slice(1);
|
|
1357
|
-
}
|
|
1358
|
-
const lines = normalized.split("\n");
|
|
1359
|
-
const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
|
|
2568
|
+
var _a, _b;
|
|
2569
|
+
const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
|
|
1360
2570
|
if (nonEmptyLines.length === 0) {
|
|
1361
2571
|
return {};
|
|
1362
2572
|
}
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
})
|
|
1368
|
-
|
|
1369
|
-
if (minIndent > 0) {
|
|
1370
|
-
normalized = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
2573
|
+
const parsed = parseYamlDocumentAsMapping(normalized);
|
|
2574
|
+
if (parsed.errors.length > 0) {
|
|
2575
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
|
|
2576
|
+
errors: parsed.errors
|
|
2577
|
+
});
|
|
2578
|
+
return null;
|
|
1371
2579
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
2580
|
+
if (parsed.value === null) {
|
|
2581
|
+
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
|
|
2582
|
+
got: "non-mapping"
|
|
2583
|
+
});
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
return parsed.value;
|
|
2587
|
+
}
|
|
2588
|
+
function parseYamlContentForStreamProgress(yamlContent) {
|
|
2589
|
+
const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
|
|
2590
|
+
if (nonEmptyLines.length === 0) {
|
|
2591
|
+
return {};
|
|
2592
|
+
}
|
|
2593
|
+
let candidate = normalized;
|
|
2594
|
+
while (true) {
|
|
2595
|
+
const parsed = parseYamlDocumentAsMapping(candidate);
|
|
2596
|
+
if (parsed.errors.length === 0 && !hasUnstableProgressTail(candidate)) {
|
|
2597
|
+
if (candidate.trim().length === 0 && normalized.trim().length > 0) {
|
|
2598
|
+
return null;
|
|
2599
|
+
}
|
|
2600
|
+
return stabilizeParsedValueForStreamProgress(parsed.value, candidate);
|
|
1379
2601
|
}
|
|
1380
|
-
const
|
|
1381
|
-
if (
|
|
1382
|
-
return
|
|
2602
|
+
const truncated = dropLastMeaningfulLine(candidate);
|
|
2603
|
+
if (truncated == null) {
|
|
2604
|
+
return null;
|
|
1383
2605
|
}
|
|
1384
|
-
if (
|
|
1385
|
-
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
|
|
1386
|
-
got: typeof result
|
|
1387
|
-
});
|
|
2606
|
+
if (truncated === candidate) {
|
|
1388
2607
|
return null;
|
|
1389
2608
|
}
|
|
1390
|
-
|
|
1391
|
-
} catch (error) {
|
|
1392
|
-
(_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, "Failed to parse YAML content", { error });
|
|
1393
|
-
return null;
|
|
2609
|
+
candidate = truncated;
|
|
1394
2610
|
}
|
|
1395
2611
|
}
|
|
1396
2612
|
function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
|
|
@@ -1406,7 +2622,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1406
2622
|
if (parsedArgs !== null) {
|
|
1407
2623
|
processedElements.push({
|
|
1408
2624
|
type: "tool-call",
|
|
1409
|
-
toolCallId:
|
|
2625
|
+
toolCallId: generateToolCallId(),
|
|
1410
2626
|
toolName: tc.toolName,
|
|
1411
2627
|
input: JSON.stringify(parsedArgs)
|
|
1412
2628
|
});
|
|
@@ -1419,38 +2635,6 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1419
2635
|
}
|
|
1420
2636
|
return tc.endIndex;
|
|
1421
2637
|
}
|
|
1422
|
-
function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
1423
|
-
return (controller, text) => {
|
|
1424
|
-
const content = text;
|
|
1425
|
-
if (content) {
|
|
1426
|
-
if (!getCurrentTextId()) {
|
|
1427
|
-
const newId = generateId();
|
|
1428
|
-
setCurrentTextId(newId);
|
|
1429
|
-
controller.enqueue({
|
|
1430
|
-
type: "text-start",
|
|
1431
|
-
id: newId
|
|
1432
|
-
});
|
|
1433
|
-
setHasEmittedTextStart(true);
|
|
1434
|
-
}
|
|
1435
|
-
controller.enqueue({
|
|
1436
|
-
type: "text-delta",
|
|
1437
|
-
id: getCurrentTextId(),
|
|
1438
|
-
delta: content
|
|
1439
|
-
});
|
|
1440
|
-
}
|
|
1441
|
-
const currentTextId = getCurrentTextId();
|
|
1442
|
-
if (currentTextId && !text) {
|
|
1443
|
-
if (getHasEmittedTextStart()) {
|
|
1444
|
-
controller.enqueue({
|
|
1445
|
-
type: "text-end",
|
|
1446
|
-
id: currentTextId
|
|
1447
|
-
});
|
|
1448
|
-
setHasEmittedTextStart(false);
|
|
1449
|
-
}
|
|
1450
|
-
setCurrentTextId(null);
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
}
|
|
1454
2638
|
function findEarliestToolTag2(buffer, toolNames) {
|
|
1455
2639
|
let bestIndex = -1;
|
|
1456
2640
|
let bestName = "";
|
|
@@ -1458,8 +2642,9 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1458
2642
|
let bestTagLength = 0;
|
|
1459
2643
|
for (const name of toolNames) {
|
|
1460
2644
|
const openTag = `<${name}>`;
|
|
1461
|
-
const selfTagRegex =
|
|
2645
|
+
const selfTagRegex = getSelfClosingTagPattern2(name);
|
|
1462
2646
|
const idxOpen = buffer.indexOf(openTag);
|
|
2647
|
+
selfTagRegex.lastIndex = 0;
|
|
1463
2648
|
const selfMatch = selfTagRegex.exec(buffer);
|
|
1464
2649
|
const idxSelf = selfMatch ? selfMatch.index : -1;
|
|
1465
2650
|
if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
|
|
@@ -1482,6 +2667,29 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1482
2667
|
tagLength: bestTagLength
|
|
1483
2668
|
};
|
|
1484
2669
|
}
|
|
2670
|
+
function stripTrailingPartialCloseTag(content, toolName) {
|
|
2671
|
+
const closeTag = `</${toolName}>`;
|
|
2672
|
+
const lastLineBreakIndex = Math.max(
|
|
2673
|
+
content.lastIndexOf("\n"),
|
|
2674
|
+
content.lastIndexOf("\r")
|
|
2675
|
+
);
|
|
2676
|
+
const lineStartIndex = lastLineBreakIndex === -1 ? 0 : lastLineBreakIndex + 1;
|
|
2677
|
+
const trailingLine = content.slice(lineStartIndex);
|
|
2678
|
+
const trimmedTrailingLine = trailingLine.trim();
|
|
2679
|
+
if (trimmedTrailingLine.length === 0 || !trimmedTrailingLine.startsWith("</") || trimmedTrailingLine === closeTag || !closeTag.startsWith(trimmedTrailingLine)) {
|
|
2680
|
+
return content;
|
|
2681
|
+
}
|
|
2682
|
+
const leadingWhitespaceLength = trailingLine.length - trailingLine.trimStart().length;
|
|
2683
|
+
const preservedLeadingWhitespace = trailingLine.slice(
|
|
2684
|
+
0,
|
|
2685
|
+
leadingWhitespaceLength
|
|
2686
|
+
);
|
|
2687
|
+
const contentWithoutPartial = `${content.slice(
|
|
2688
|
+
0,
|
|
2689
|
+
lineStartIndex
|
|
2690
|
+
)}${preservedLeadingWhitespace}`;
|
|
2691
|
+
return contentWithoutPartial.trimEnd();
|
|
2692
|
+
}
|
|
1485
2693
|
var yamlProtocol = (_protocolOptions) => {
|
|
1486
2694
|
return {
|
|
1487
2695
|
formatTools({ tools, toolSystemPromptTemplate }) {
|
|
@@ -1507,18 +2715,32 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1507
2715
|
}
|
|
1508
2716
|
const processedElements = [];
|
|
1509
2717
|
let currentIndex = 0;
|
|
1510
|
-
|
|
2718
|
+
let parseText = text;
|
|
2719
|
+
let toolCalls = findToolCalls2(parseText, toolNames);
|
|
2720
|
+
if (toolCalls.length === 0) {
|
|
2721
|
+
const repaired = tryRepairXmlSelfClosingRootWithBody(
|
|
2722
|
+
parseText,
|
|
2723
|
+
toolNames
|
|
2724
|
+
);
|
|
2725
|
+
if (repaired) {
|
|
2726
|
+
const repairedCalls = findToolCalls2(repaired, toolNames);
|
|
2727
|
+
if (repairedCalls.length > 0) {
|
|
2728
|
+
parseText = repaired;
|
|
2729
|
+
toolCalls = repairedCalls;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
1511
2733
|
for (const tc of toolCalls) {
|
|
1512
2734
|
currentIndex = processToolCallMatch(
|
|
1513
|
-
|
|
2735
|
+
parseText,
|
|
1514
2736
|
tc,
|
|
1515
2737
|
currentIndex,
|
|
1516
2738
|
processedElements,
|
|
1517
2739
|
options
|
|
1518
2740
|
);
|
|
1519
2741
|
}
|
|
1520
|
-
if (currentIndex <
|
|
1521
|
-
addTextSegment(
|
|
2742
|
+
if (currentIndex < parseText.length) {
|
|
2743
|
+
addTextSegment(parseText.substring(currentIndex), processedElements);
|
|
1522
2744
|
}
|
|
1523
2745
|
return processedElements;
|
|
1524
2746
|
},
|
|
@@ -1528,7 +2750,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1528
2750
|
let currentToolCall = null;
|
|
1529
2751
|
let currentTextId = null;
|
|
1530
2752
|
let hasEmittedTextStart = false;
|
|
1531
|
-
const flushText =
|
|
2753
|
+
const flushText = createFlushTextHandler(
|
|
1532
2754
|
() => currentTextId,
|
|
1533
2755
|
(newId) => {
|
|
1534
2756
|
currentTextId = newId;
|
|
@@ -1538,33 +2760,128 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1538
2760
|
hasEmittedTextStart = value;
|
|
1539
2761
|
}
|
|
1540
2762
|
);
|
|
1541
|
-
const
|
|
2763
|
+
const emitToolInputProgress2 = (controller, toolContent) => {
|
|
2764
|
+
if (!currentToolCall) {
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
const parsedArgs = parseYamlContentForStreamProgress(toolContent);
|
|
2768
|
+
if (parsedArgs === null) {
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
const fullInput = JSON.stringify(parsedArgs);
|
|
2772
|
+
if (fullInput === "{}" && toolContent.trim().length === 0) {
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
const prefixCandidate = toIncompleteJsonPrefix(fullInput);
|
|
2776
|
+
emitPrefixDelta({
|
|
2777
|
+
controller,
|
|
2778
|
+
id: currentToolCall.toolCallId,
|
|
2779
|
+
state: currentToolCall,
|
|
2780
|
+
candidate: prefixCandidate
|
|
2781
|
+
});
|
|
2782
|
+
};
|
|
2783
|
+
const processToolCallEnd = (controller, toolContent, toolName, toolCallId) => {
|
|
2784
|
+
var _a;
|
|
2785
|
+
const parsedArgs = parseYamlContent(toolContent, options);
|
|
2786
|
+
flushText(controller);
|
|
2787
|
+
if (parsedArgs !== null) {
|
|
2788
|
+
const finalInput = JSON.stringify(parsedArgs);
|
|
2789
|
+
if (currentToolCall && currentToolCall.toolCallId === toolCallId) {
|
|
2790
|
+
emitFinalRemainder({
|
|
2791
|
+
controller,
|
|
2792
|
+
id: toolCallId,
|
|
2793
|
+
state: currentToolCall,
|
|
2794
|
+
finalFullJson: finalInput,
|
|
2795
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2796
|
+
});
|
|
2797
|
+
}
|
|
2798
|
+
controller.enqueue({
|
|
2799
|
+
type: "tool-input-end",
|
|
2800
|
+
id: toolCallId
|
|
2801
|
+
});
|
|
2802
|
+
controller.enqueue({
|
|
2803
|
+
type: "tool-call",
|
|
2804
|
+
toolCallId,
|
|
2805
|
+
toolName,
|
|
2806
|
+
input: finalInput
|
|
2807
|
+
});
|
|
2808
|
+
} else {
|
|
2809
|
+
controller.enqueue({
|
|
2810
|
+
type: "tool-input-end",
|
|
2811
|
+
id: toolCallId
|
|
2812
|
+
});
|
|
2813
|
+
const original = `<${toolName}>${toolContent}</${toolName}>`;
|
|
2814
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
|
|
2815
|
+
toolCall: original
|
|
2816
|
+
});
|
|
2817
|
+
if (shouldEmitRawToolCallTextOnError3(options)) {
|
|
2818
|
+
flushText(controller, original);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
const finalizeUnclosedToolCall = (controller) => {
|
|
1542
2823
|
var _a;
|
|
1543
|
-
|
|
2824
|
+
if (!currentToolCall) {
|
|
2825
|
+
return;
|
|
2826
|
+
}
|
|
2827
|
+
emitToolInputProgress2(controller, buffer);
|
|
2828
|
+
const { name: toolName, toolCallId } = currentToolCall;
|
|
2829
|
+
const reconciledBuffer = stripTrailingPartialCloseTag(buffer, toolName);
|
|
2830
|
+
const parsedArgs = parseYamlContent(reconciledBuffer, options);
|
|
1544
2831
|
flushText(controller);
|
|
1545
2832
|
if (parsedArgs !== null) {
|
|
2833
|
+
const finalInput = JSON.stringify(parsedArgs);
|
|
2834
|
+
emitFinalRemainder({
|
|
2835
|
+
controller,
|
|
2836
|
+
id: toolCallId,
|
|
2837
|
+
state: currentToolCall,
|
|
2838
|
+
finalFullJson: finalInput,
|
|
2839
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2840
|
+
});
|
|
2841
|
+
controller.enqueue({
|
|
2842
|
+
type: "tool-input-end",
|
|
2843
|
+
id: toolCallId
|
|
2844
|
+
});
|
|
1546
2845
|
controller.enqueue({
|
|
1547
2846
|
type: "tool-call",
|
|
1548
|
-
toolCallId
|
|
2847
|
+
toolCallId,
|
|
1549
2848
|
toolName,
|
|
1550
|
-
input:
|
|
2849
|
+
input: finalInput
|
|
1551
2850
|
});
|
|
1552
2851
|
} else {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
2852
|
+
controller.enqueue({
|
|
2853
|
+
type: "tool-input-end",
|
|
2854
|
+
id: toolCallId
|
|
1556
2855
|
});
|
|
1557
|
-
|
|
2856
|
+
const unfinishedContent = `<${toolName}>${buffer}`;
|
|
2857
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
2858
|
+
options,
|
|
2859
|
+
"Could not complete streaming YAML tool call at finish.",
|
|
2860
|
+
{ toolCall: unfinishedContent }
|
|
2861
|
+
);
|
|
2862
|
+
if (shouldEmitRawToolCallTextOnError3(options)) {
|
|
2863
|
+
flushText(controller, unfinishedContent);
|
|
2864
|
+
}
|
|
1558
2865
|
}
|
|
2866
|
+
buffer = "";
|
|
2867
|
+
currentToolCall = null;
|
|
1559
2868
|
};
|
|
1560
2869
|
const handlePendingToolCall = (controller, endTag, toolName) => {
|
|
2870
|
+
var _a;
|
|
1561
2871
|
const endIdx = buffer.indexOf(endTag);
|
|
1562
2872
|
if (endIdx === -1) {
|
|
2873
|
+
emitToolInputProgress2(controller, buffer);
|
|
1563
2874
|
return false;
|
|
1564
2875
|
}
|
|
1565
2876
|
const content = buffer.substring(0, endIdx);
|
|
2877
|
+
emitToolInputProgress2(controller, content);
|
|
1566
2878
|
buffer = buffer.substring(endIdx + endTag.length);
|
|
1567
|
-
processToolCallEnd(
|
|
2879
|
+
processToolCallEnd(
|
|
2880
|
+
controller,
|
|
2881
|
+
content,
|
|
2882
|
+
toolName,
|
|
2883
|
+
(_a = currentToolCall == null ? void 0 : currentToolCall.toolCallId) != null ? _a : generateToolCallId()
|
|
2884
|
+
);
|
|
1568
2885
|
currentToolCall = null;
|
|
1569
2886
|
return true;
|
|
1570
2887
|
};
|
|
@@ -1581,13 +2898,35 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1581
2898
|
if (tagIndex > 0) {
|
|
1582
2899
|
flushText(controller, buffer.substring(0, tagIndex));
|
|
1583
2900
|
}
|
|
2901
|
+
flushText(controller);
|
|
1584
2902
|
if (selfClosing) {
|
|
1585
2903
|
buffer = buffer.substring(tagIndex + tagLength);
|
|
1586
|
-
|
|
2904
|
+
const toolCallId = generateToolCallId();
|
|
2905
|
+
currentToolCall = {
|
|
2906
|
+
name: tagName,
|
|
2907
|
+
toolCallId,
|
|
2908
|
+
emittedInput: ""
|
|
2909
|
+
};
|
|
2910
|
+
controller.enqueue({
|
|
2911
|
+
type: "tool-input-start",
|
|
2912
|
+
id: toolCallId,
|
|
2913
|
+
toolName: tagName
|
|
2914
|
+
});
|
|
2915
|
+
processToolCallEnd(controller, "", tagName, toolCallId);
|
|
2916
|
+
currentToolCall = null;
|
|
1587
2917
|
} else {
|
|
1588
2918
|
const startTag = `<${tagName}>`;
|
|
1589
2919
|
buffer = buffer.substring(tagIndex + startTag.length);
|
|
1590
|
-
currentToolCall = {
|
|
2920
|
+
currentToolCall = {
|
|
2921
|
+
name: tagName,
|
|
2922
|
+
toolCallId: generateToolCallId(),
|
|
2923
|
+
emittedInput: ""
|
|
2924
|
+
};
|
|
2925
|
+
controller.enqueue({
|
|
2926
|
+
type: "tool-input-start",
|
|
2927
|
+
id: currentToolCall.toolCallId,
|
|
2928
|
+
toolName: tagName
|
|
2929
|
+
});
|
|
1591
2930
|
}
|
|
1592
2931
|
};
|
|
1593
2932
|
const processBuffer = (controller) => {
|
|
@@ -1614,8 +2953,19 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1614
2953
|
return new TransformStream({
|
|
1615
2954
|
transform(chunk, controller) {
|
|
1616
2955
|
var _a;
|
|
2956
|
+
if (chunk.type === "finish") {
|
|
2957
|
+
if (currentToolCall) {
|
|
2958
|
+
finalizeUnclosedToolCall(controller);
|
|
2959
|
+
} else if (buffer) {
|
|
2960
|
+
flushText(controller, buffer);
|
|
2961
|
+
buffer = "";
|
|
2962
|
+
}
|
|
2963
|
+
flushText(controller);
|
|
2964
|
+
controller.enqueue(chunk);
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
1617
2967
|
if (chunk.type !== "text-delta") {
|
|
1618
|
-
if (buffer) {
|
|
2968
|
+
if (!currentToolCall && buffer) {
|
|
1619
2969
|
flushText(controller, buffer);
|
|
1620
2970
|
buffer = "";
|
|
1621
2971
|
}
|
|
@@ -1628,10 +2978,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1628
2978
|
},
|
|
1629
2979
|
flush(controller) {
|
|
1630
2980
|
if (currentToolCall) {
|
|
1631
|
-
|
|
1632
|
-
flushText(controller, unfinishedContent);
|
|
1633
|
-
buffer = "";
|
|
1634
|
-
currentToolCall = null;
|
|
2981
|
+
finalizeUnclosedToolCall(controller);
|
|
1635
2982
|
} else if (buffer) {
|
|
1636
2983
|
flushText(controller, buffer);
|
|
1637
2984
|
buffer = "";
|
|
@@ -1737,17 +3084,56 @@ function encodeOriginalTools(tools) {
|
|
|
1737
3084
|
inputSchema: JSON.stringify(t.inputSchema)
|
|
1738
3085
|
}))) || [];
|
|
1739
3086
|
}
|
|
1740
|
-
function decodeOriginalTools(originalTools) {
|
|
3087
|
+
function decodeOriginalTools(originalTools, options) {
|
|
3088
|
+
var _a, _b, _c;
|
|
1741
3089
|
if (!originalTools) {
|
|
1742
3090
|
return [];
|
|
1743
3091
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
3092
|
+
const decodedTools = [];
|
|
3093
|
+
for (const [index, tool] of originalTools.entries()) {
|
|
3094
|
+
if (!tool || typeof tool.name !== "string") {
|
|
3095
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Invalid originalTools entry: missing tool name", {
|
|
3096
|
+
index,
|
|
3097
|
+
tool
|
|
3098
|
+
});
|
|
3099
|
+
continue;
|
|
3100
|
+
}
|
|
3101
|
+
if (typeof tool.inputSchema !== "string") {
|
|
3102
|
+
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
|
|
3103
|
+
options,
|
|
3104
|
+
"Invalid originalTools entry: inputSchema must be a string",
|
|
3105
|
+
{
|
|
3106
|
+
index,
|
|
3107
|
+
toolName: tool.name
|
|
3108
|
+
}
|
|
3109
|
+
);
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
try {
|
|
3113
|
+
decodedTools.push({
|
|
3114
|
+
type: "function",
|
|
3115
|
+
name: tool.name,
|
|
3116
|
+
inputSchema: JSON.parse(tool.inputSchema)
|
|
3117
|
+
});
|
|
3118
|
+
} catch (error) {
|
|
3119
|
+
(_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(
|
|
3120
|
+
options,
|
|
3121
|
+
"Failed to decode originalTools input schema, using permissive fallback schema",
|
|
3122
|
+
{
|
|
3123
|
+
index,
|
|
3124
|
+
toolName: tool.name,
|
|
3125
|
+
inputSchema: tool.inputSchema,
|
|
3126
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3127
|
+
}
|
|
3128
|
+
);
|
|
3129
|
+
decodedTools.push({
|
|
3130
|
+
type: "function",
|
|
3131
|
+
name: tool.name,
|
|
3132
|
+
inputSchema: { type: "object" }
|
|
3133
|
+
});
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
return decodedTools;
|
|
1751
3137
|
}
|
|
1752
3138
|
function extractToolNamesFromOriginalTools(originalTools) {
|
|
1753
3139
|
return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
|
|
@@ -1770,25 +3156,336 @@ function hasInputProperty(obj) {
|
|
|
1770
3156
|
return typeof obj === "object" && obj !== null && "input" in obj;
|
|
1771
3157
|
}
|
|
1772
3158
|
|
|
1773
|
-
// src/
|
|
1774
|
-
|
|
1775
|
-
|
|
3159
|
+
// src/core/utils/generated-text-json-recovery.ts
|
|
3160
|
+
function isRecord(value) {
|
|
3161
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3162
|
+
}
|
|
3163
|
+
function safeStringify2(value) {
|
|
3164
|
+
try {
|
|
3165
|
+
return JSON.stringify(value != null ? value : {});
|
|
3166
|
+
} catch (e) {
|
|
3167
|
+
return "{}";
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
function parseJsonCandidate(candidateText) {
|
|
3171
|
+
try {
|
|
3172
|
+
return parse(candidateText);
|
|
3173
|
+
} catch (e) {
|
|
3174
|
+
return void 0;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
function extractCodeBlockCandidates(text) {
|
|
3178
|
+
var _a, _b;
|
|
3179
|
+
const codeBlockRegex = /```(?:json|yaml|xml)?\s*([\s\S]*?)```/gi;
|
|
3180
|
+
const candidates = [];
|
|
3181
|
+
let match;
|
|
3182
|
+
while (true) {
|
|
3183
|
+
match = codeBlockRegex.exec(text);
|
|
3184
|
+
if (!match) {
|
|
3185
|
+
break;
|
|
3186
|
+
}
|
|
3187
|
+
const body = (_a = match[1]) == null ? void 0 : _a.trim();
|
|
3188
|
+
if (body) {
|
|
3189
|
+
const startIndex = (_b = match.index) != null ? _b : 0;
|
|
3190
|
+
const endIndex = startIndex + match[0].length;
|
|
3191
|
+
candidates.push({
|
|
3192
|
+
text: body,
|
|
3193
|
+
startIndex,
|
|
3194
|
+
endIndex
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
return candidates;
|
|
3199
|
+
}
|
|
3200
|
+
function scanJsonChar(state, char) {
|
|
3201
|
+
if (state.inString) {
|
|
3202
|
+
if (state.escaping) {
|
|
3203
|
+
return { ...state, escaping: false };
|
|
3204
|
+
}
|
|
3205
|
+
if (char === "\\") {
|
|
3206
|
+
return { ...state, escaping: true };
|
|
3207
|
+
}
|
|
3208
|
+
if (char === '"') {
|
|
3209
|
+
return { ...state, inString: false };
|
|
3210
|
+
}
|
|
3211
|
+
return state;
|
|
3212
|
+
}
|
|
3213
|
+
if (char === '"') {
|
|
3214
|
+
return { ...state, inString: true };
|
|
3215
|
+
}
|
|
3216
|
+
if (char === "{") {
|
|
3217
|
+
return { ...state, depth: state.depth + 1 };
|
|
3218
|
+
}
|
|
3219
|
+
if (char === "}") {
|
|
3220
|
+
return { ...state, depth: Math.max(0, state.depth - 1) };
|
|
3221
|
+
}
|
|
3222
|
+
return state;
|
|
3223
|
+
}
|
|
3224
|
+
function extractBalancedJsonObjects(text) {
|
|
3225
|
+
const maxCandidateLength = 1e4;
|
|
3226
|
+
const candidates = [];
|
|
3227
|
+
let state = { depth: 0, inString: false, escaping: false };
|
|
3228
|
+
let currentStart = null;
|
|
3229
|
+
let ignoreCurrent = false;
|
|
3230
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
3231
|
+
const char = text[index];
|
|
3232
|
+
if (!state.inString && char === "{" && state.depth === 0) {
|
|
3233
|
+
currentStart = index;
|
|
3234
|
+
ignoreCurrent = false;
|
|
3235
|
+
}
|
|
3236
|
+
state = scanJsonChar(state, char);
|
|
3237
|
+
if (currentStart !== null && !ignoreCurrent && index - currentStart + 1 > maxCandidateLength) {
|
|
3238
|
+
ignoreCurrent = true;
|
|
3239
|
+
}
|
|
3240
|
+
if (!state.inString && char === "}" && state.depth === 0) {
|
|
3241
|
+
if (currentStart !== null && !ignoreCurrent) {
|
|
3242
|
+
const endIndex = index + 1;
|
|
3243
|
+
const candidate = text.slice(currentStart, endIndex);
|
|
3244
|
+
if (candidate.length > 1) {
|
|
3245
|
+
candidates.push({
|
|
3246
|
+
text: candidate,
|
|
3247
|
+
startIndex: currentStart,
|
|
3248
|
+
endIndex
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
currentStart = null;
|
|
3253
|
+
ignoreCurrent = false;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
return candidates;
|
|
3257
|
+
}
|
|
3258
|
+
function extractTaggedToolCallCandidates(rawText) {
|
|
3259
|
+
var _a, _b;
|
|
3260
|
+
const toolCallRegex = /<tool_call>([\s\S]*?)<\/tool_call>/gi;
|
|
3261
|
+
const candidates = [];
|
|
3262
|
+
let match;
|
|
3263
|
+
while (true) {
|
|
3264
|
+
match = toolCallRegex.exec(rawText);
|
|
3265
|
+
if (!match) {
|
|
3266
|
+
break;
|
|
3267
|
+
}
|
|
3268
|
+
const body = (_a = match[1]) == null ? void 0 : _a.trim();
|
|
3269
|
+
if (!body) {
|
|
3270
|
+
continue;
|
|
3271
|
+
}
|
|
3272
|
+
const startIndex = (_b = match.index) != null ? _b : 0;
|
|
3273
|
+
const endIndex = startIndex + match[0].length;
|
|
3274
|
+
candidates.push({
|
|
3275
|
+
text: body,
|
|
3276
|
+
startIndex,
|
|
3277
|
+
endIndex
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
3280
|
+
return candidates;
|
|
3281
|
+
}
|
|
3282
|
+
function extractJsonLikeCandidates(rawText) {
|
|
3283
|
+
return mergeJsonCandidatesByStart(
|
|
3284
|
+
extractTaggedToolCallCandidates(rawText),
|
|
3285
|
+
extractCodeBlockCandidates(rawText),
|
|
3286
|
+
extractBalancedJsonObjects(rawText)
|
|
3287
|
+
);
|
|
3288
|
+
}
|
|
3289
|
+
function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
|
|
3290
|
+
return [...tagged, ...codeBlocks, ...balanced].sort(
|
|
3291
|
+
(a, b) => a.startIndex !== b.startIndex ? a.startIndex - b.startIndex : b.endIndex - a.endIndex
|
|
3292
|
+
);
|
|
3293
|
+
}
|
|
3294
|
+
function toToolCallPart(candidate) {
|
|
3295
|
+
return {
|
|
3296
|
+
type: "tool-call",
|
|
3297
|
+
toolCallId: generateToolCallId(),
|
|
3298
|
+
toolName: candidate.toolName,
|
|
3299
|
+
input: candidate.input
|
|
3300
|
+
};
|
|
3301
|
+
}
|
|
3302
|
+
function toRecoveredParts(text, candidate, toolCallPart) {
|
|
3303
|
+
const out = [];
|
|
3304
|
+
const prefix = text.slice(0, candidate.startIndex);
|
|
3305
|
+
if (prefix.length > 0) {
|
|
3306
|
+
out.push({ type: "text", text: prefix });
|
|
3307
|
+
}
|
|
3308
|
+
out.push(toolCallPart);
|
|
3309
|
+
const suffix = text.slice(candidate.endIndex);
|
|
3310
|
+
if (suffix.length > 0) {
|
|
3311
|
+
out.push({ type: "text", text: suffix });
|
|
3312
|
+
}
|
|
3313
|
+
return out;
|
|
3314
|
+
}
|
|
3315
|
+
function parseAsToolPayload(payload, tools) {
|
|
3316
|
+
if (!isRecord(payload)) {
|
|
3317
|
+
return null;
|
|
3318
|
+
}
|
|
3319
|
+
const toolName = typeof payload.name === "string" && payload.name.trim().length > 0 ? payload.name.trim() : null;
|
|
3320
|
+
if (!toolName) {
|
|
3321
|
+
return null;
|
|
3322
|
+
}
|
|
3323
|
+
if (!tools.some((tool) => tool.name === toolName)) {
|
|
3324
|
+
return null;
|
|
3325
|
+
}
|
|
3326
|
+
const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
|
|
3327
|
+
if (!isRecord(rawArgs)) {
|
|
3328
|
+
return null;
|
|
3329
|
+
}
|
|
3330
|
+
return {
|
|
3331
|
+
toolName,
|
|
3332
|
+
input: safeStringify2(rawArgs)
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
function isLikelyArgumentsShapeForTool(args, tool) {
|
|
3336
|
+
const unwrapped = unwrapJsonSchema(tool.inputSchema);
|
|
3337
|
+
if (!isRecord(unwrapped)) {
|
|
3338
|
+
return false;
|
|
3339
|
+
}
|
|
3340
|
+
if (getSchemaType(unwrapped) !== "object") {
|
|
3341
|
+
return false;
|
|
3342
|
+
}
|
|
3343
|
+
const properties = unwrapped.properties;
|
|
3344
|
+
if (!isRecord(properties)) {
|
|
3345
|
+
return false;
|
|
3346
|
+
}
|
|
3347
|
+
const keys = Object.keys(args);
|
|
3348
|
+
if (keys.length === 0) {
|
|
3349
|
+
return false;
|
|
3350
|
+
}
|
|
3351
|
+
const knownKeys = keys.filter((key) => Object.hasOwn(properties, key));
|
|
3352
|
+
if (knownKeys.length === 0) {
|
|
3353
|
+
return false;
|
|
3354
|
+
}
|
|
3355
|
+
if (unwrapped.additionalProperties === false && knownKeys.length !== keys.length) {
|
|
3356
|
+
return false;
|
|
3357
|
+
}
|
|
3358
|
+
return true;
|
|
3359
|
+
}
|
|
3360
|
+
function parseAsArgumentsOnly(payload, tools) {
|
|
3361
|
+
if (tools.length !== 1) {
|
|
3362
|
+
return null;
|
|
3363
|
+
}
|
|
3364
|
+
if (!isRecord(payload)) {
|
|
3365
|
+
return null;
|
|
3366
|
+
}
|
|
3367
|
+
const hasNameEnvelope = Object.hasOwn(payload, "name") && typeof payload.name === "string" && payload.name.length > 0;
|
|
3368
|
+
const hasArgumentsEnvelope = Object.hasOwn(payload, "arguments") && (typeof payload.arguments === "string" || isRecord(payload.arguments));
|
|
3369
|
+
if (hasNameEnvelope || hasArgumentsEnvelope) {
|
|
3370
|
+
return null;
|
|
3371
|
+
}
|
|
3372
|
+
const tool = tools[0];
|
|
3373
|
+
if (!isLikelyArgumentsShapeForTool(payload, tool)) {
|
|
3374
|
+
return null;
|
|
3375
|
+
}
|
|
3376
|
+
return {
|
|
3377
|
+
toolName: tool.name,
|
|
3378
|
+
input: safeStringify2(payload)
|
|
3379
|
+
};
|
|
3380
|
+
}
|
|
3381
|
+
function recoverToolCallFromJsonCandidates(text, tools) {
|
|
3382
|
+
if (tools.length === 0) {
|
|
3383
|
+
return null;
|
|
3384
|
+
}
|
|
3385
|
+
const jsonCandidates = extractJsonLikeCandidates(text);
|
|
3386
|
+
for (const jsonCandidate of jsonCandidates) {
|
|
3387
|
+
const parsed = parseJsonCandidate(jsonCandidate.text);
|
|
3388
|
+
if (parsed === void 0) {
|
|
3389
|
+
continue;
|
|
3390
|
+
}
|
|
3391
|
+
const toolPayload = parseAsToolPayload(parsed, tools);
|
|
3392
|
+
if (toolPayload) {
|
|
3393
|
+
return toRecoveredParts(text, jsonCandidate, toToolCallPart(toolPayload));
|
|
3394
|
+
}
|
|
3395
|
+
const argsPayload = parseAsArgumentsOnly(parsed, tools);
|
|
3396
|
+
if (argsPayload) {
|
|
3397
|
+
return toRecoveredParts(text, jsonCandidate, toToolCallPart(argsPayload));
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
return null;
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
// src/core/utils/tool-call-coercion.ts
|
|
3404
|
+
function coerceToolCallInput(toolName, input, tools) {
|
|
1776
3405
|
var _a;
|
|
3406
|
+
let args = {};
|
|
3407
|
+
if (typeof input === "string") {
|
|
3408
|
+
try {
|
|
3409
|
+
args = JSON.parse(input);
|
|
3410
|
+
} catch (e) {
|
|
3411
|
+
return;
|
|
3412
|
+
}
|
|
3413
|
+
} else if (input && typeof input === "object") {
|
|
3414
|
+
args = input;
|
|
3415
|
+
} else {
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
const schema = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
|
|
3419
|
+
const coerced = coerceBySchema(args, schema);
|
|
3420
|
+
return JSON.stringify(coerced != null ? coerced : {});
|
|
3421
|
+
}
|
|
3422
|
+
function coerceToolCallPart(part, tools) {
|
|
3423
|
+
const coercedInput = coerceToolCallInput(part.toolName, part.input, tools);
|
|
3424
|
+
if (coercedInput === void 0) {
|
|
3425
|
+
return part;
|
|
3426
|
+
}
|
|
3427
|
+
return {
|
|
3428
|
+
...part,
|
|
3429
|
+
input: coercedInput
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
// src/core/utils/tool-choice.ts
|
|
3434
|
+
function ensureNonEmptyToolName(name) {
|
|
3435
|
+
if (typeof name !== "string") {
|
|
3436
|
+
return "unknown";
|
|
3437
|
+
}
|
|
3438
|
+
const trimmed = name.trim();
|
|
3439
|
+
return trimmed.length > 0 ? trimmed : "unknown";
|
|
3440
|
+
}
|
|
3441
|
+
function safeStringify3(value) {
|
|
1777
3442
|
try {
|
|
1778
|
-
return JSON.
|
|
3443
|
+
return JSON.stringify(value != null ? value : {});
|
|
3444
|
+
} catch (e) {
|
|
3445
|
+
return "{}";
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
function parseToolChoicePayload({
|
|
3449
|
+
text,
|
|
3450
|
+
tools,
|
|
3451
|
+
onError,
|
|
3452
|
+
errorMessage
|
|
3453
|
+
}) {
|
|
3454
|
+
let parsed;
|
|
3455
|
+
try {
|
|
3456
|
+
parsed = JSON.parse(text);
|
|
1779
3457
|
} catch (error) {
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
3458
|
+
onError == null ? void 0 : onError(errorMessage, {
|
|
3459
|
+
text,
|
|
3460
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3461
|
+
});
|
|
3462
|
+
return { toolName: "unknown", input: "{}" };
|
|
3463
|
+
}
|
|
3464
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
3465
|
+
onError == null ? void 0 : onError("toolChoice JSON payload must be an object", {
|
|
3466
|
+
parsedType: typeof parsed,
|
|
3467
|
+
parsed
|
|
3468
|
+
});
|
|
3469
|
+
return { toolName: "unknown", input: "{}" };
|
|
1790
3470
|
}
|
|
3471
|
+
const payload = parsed;
|
|
3472
|
+
const toolName = ensureNonEmptyToolName(payload.name);
|
|
3473
|
+
const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
|
|
3474
|
+
if (rawArgs == null || typeof rawArgs !== "object" || Array.isArray(rawArgs)) {
|
|
3475
|
+
onError == null ? void 0 : onError("toolChoice arguments must be a JSON object", {
|
|
3476
|
+
toolName,
|
|
3477
|
+
arguments: rawArgs
|
|
3478
|
+
});
|
|
3479
|
+
return { toolName, input: "{}" };
|
|
3480
|
+
}
|
|
3481
|
+
const coercedInput = coerceToolCallInput(toolName, rawArgs, tools);
|
|
3482
|
+
return {
|
|
3483
|
+
toolName,
|
|
3484
|
+
input: coercedInput != null ? coercedInput : safeStringify3(rawArgs)
|
|
3485
|
+
};
|
|
1791
3486
|
}
|
|
3487
|
+
|
|
3488
|
+
// src/generate-handler.ts
|
|
1792
3489
|
function logDebugSummary(debugSummary, toolCall, originText) {
|
|
1793
3490
|
if (debugSummary) {
|
|
1794
3491
|
debugSummary.originalText = originText;
|
|
@@ -1802,25 +3499,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
|
|
|
1802
3499
|
logParsedSummary({ toolCalls: [toolCall], originalText: originText });
|
|
1803
3500
|
}
|
|
1804
3501
|
}
|
|
1805
|
-
async function handleToolChoice(doGenerate, params) {
|
|
1806
|
-
var _a, _b, _c;
|
|
3502
|
+
async function handleToolChoice(doGenerate, params, tools) {
|
|
3503
|
+
var _a, _b, _c, _d;
|
|
1807
3504
|
const result = await doGenerate();
|
|
1808
3505
|
const first = (_a = result.content) == null ? void 0 : _a[0];
|
|
1809
|
-
|
|
3506
|
+
const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
|
|
3507
|
+
let toolName = "unknown";
|
|
3508
|
+
let input = "{}";
|
|
1810
3509
|
if (first && first.type === "text") {
|
|
1811
3510
|
if (getDebugLevel() === "parse") {
|
|
1812
3511
|
logRawChunk(first.text);
|
|
1813
3512
|
}
|
|
1814
|
-
parsed =
|
|
3513
|
+
const parsed = parseToolChoicePayload({
|
|
3514
|
+
text: first.text,
|
|
3515
|
+
tools,
|
|
3516
|
+
onError,
|
|
3517
|
+
errorMessage: "Failed to parse toolChoice JSON from generated model output"
|
|
3518
|
+
});
|
|
3519
|
+
toolName = parsed.toolName;
|
|
3520
|
+
input = parsed.input;
|
|
1815
3521
|
}
|
|
1816
3522
|
const toolCall = {
|
|
1817
3523
|
type: "tool-call",
|
|
1818
|
-
toolCallId:
|
|
1819
|
-
toolName
|
|
1820
|
-
input
|
|
3524
|
+
toolCallId: generateToolCallId(),
|
|
3525
|
+
toolName,
|
|
3526
|
+
input
|
|
1821
3527
|
};
|
|
1822
3528
|
const originText = first && first.type === "text" ? first.text : "";
|
|
1823
|
-
const debugSummary = (
|
|
3529
|
+
const debugSummary = (_d = (_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) == null ? void 0 : _d.debugSummary;
|
|
1824
3530
|
logDebugSummary(debugSummary, toolCall, originText);
|
|
1825
3531
|
return {
|
|
1826
3532
|
...result,
|
|
@@ -1835,7 +3541,7 @@ function parseContent(content, protocol, tools, providerOptions) {
|
|
|
1835
3541
|
if (getDebugLevel() === "stream") {
|
|
1836
3542
|
logRawChunk(contentItem.text);
|
|
1837
3543
|
}
|
|
1838
|
-
|
|
3544
|
+
const parsedByProtocol = protocol.parseGeneratedText({
|
|
1839
3545
|
text: contentItem.text,
|
|
1840
3546
|
tools,
|
|
1841
3547
|
options: {
|
|
@@ -1843,9 +3549,20 @@ function parseContent(content, protocol, tools, providerOptions) {
|
|
|
1843
3549
|
...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
|
|
1844
3550
|
}
|
|
1845
3551
|
});
|
|
3552
|
+
const hasToolCall = parsedByProtocol.some(
|
|
3553
|
+
(part) => part.type === "tool-call"
|
|
3554
|
+
);
|
|
3555
|
+
if (hasToolCall) {
|
|
3556
|
+
return parsedByProtocol;
|
|
3557
|
+
}
|
|
3558
|
+
const recoveredFromJson = recoverToolCallFromJsonCandidates(
|
|
3559
|
+
contentItem.text,
|
|
3560
|
+
tools
|
|
3561
|
+
);
|
|
3562
|
+
return recoveredFromJson != null ? recoveredFromJson : parsedByProtocol;
|
|
1846
3563
|
});
|
|
1847
3564
|
return parsed.map(
|
|
1848
|
-
(part) =>
|
|
3565
|
+
(part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
|
|
1849
3566
|
);
|
|
1850
3567
|
}
|
|
1851
3568
|
function logParsedContent(content) {
|
|
@@ -1888,12 +3605,14 @@ async function wrapGenerate({
|
|
|
1888
3605
|
params
|
|
1889
3606
|
}) {
|
|
1890
3607
|
var _a, _b;
|
|
1891
|
-
|
|
1892
|
-
return handleToolChoice(doGenerate, params);
|
|
1893
|
-
}
|
|
3608
|
+
const onError = extractOnErrorOption(params.providerOptions);
|
|
1894
3609
|
const tools = originalToolsSchema.decode(
|
|
1895
|
-
(_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
|
|
3610
|
+
(_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
|
|
3611
|
+
onError
|
|
1896
3612
|
);
|
|
3613
|
+
if (isToolChoiceActive(params)) {
|
|
3614
|
+
return handleToolChoice(doGenerate, params, tools);
|
|
3615
|
+
}
|
|
1897
3616
|
const result = await doGenerate();
|
|
1898
3617
|
if (result.content.length === 0) {
|
|
1899
3618
|
return result;
|
|
@@ -1917,28 +3636,6 @@ async function wrapGenerate({
|
|
|
1917
3636
|
content: newContent
|
|
1918
3637
|
};
|
|
1919
3638
|
}
|
|
1920
|
-
function fixToolCallWithSchema(part, tools) {
|
|
1921
|
-
var _a;
|
|
1922
|
-
if (part.type !== "tool-call") {
|
|
1923
|
-
return part;
|
|
1924
|
-
}
|
|
1925
|
-
let args = {};
|
|
1926
|
-
if (typeof part.input === "string") {
|
|
1927
|
-
try {
|
|
1928
|
-
args = JSON.parse(part.input);
|
|
1929
|
-
} catch (e) {
|
|
1930
|
-
return part;
|
|
1931
|
-
}
|
|
1932
|
-
} else if (part.input && typeof part.input === "object") {
|
|
1933
|
-
args = part.input;
|
|
1934
|
-
}
|
|
1935
|
-
const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
|
|
1936
|
-
const coerced = coerceBySchema(args, schema);
|
|
1937
|
-
return {
|
|
1938
|
-
...part,
|
|
1939
|
-
input: JSON.stringify(coerced != null ? coerced : {})
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
3639
|
|
|
1943
3640
|
// src/core/prompts/hermes-system-prompt.ts
|
|
1944
3641
|
function hermesSystemPromptTemplate(tools) {
|
|
@@ -2334,7 +4031,6 @@ unit: celsius
|
|
|
2334
4031
|
}
|
|
2335
4032
|
|
|
2336
4033
|
// src/stream-handler.ts
|
|
2337
|
-
import { generateId as generateId3 } from "@ai-sdk/provider-utils";
|
|
2338
4034
|
async function wrapStream({
|
|
2339
4035
|
protocol,
|
|
2340
4036
|
doStream,
|
|
@@ -2342,19 +4038,22 @@ async function wrapStream({
|
|
|
2342
4038
|
params
|
|
2343
4039
|
}) {
|
|
2344
4040
|
var _a, _b, _c;
|
|
4041
|
+
const onErrorOptions = extractOnErrorOption(params.providerOptions);
|
|
4042
|
+
const tools = originalToolsSchema.decode(
|
|
4043
|
+
(_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
|
|
4044
|
+
onErrorOptions
|
|
4045
|
+
);
|
|
2345
4046
|
if (isToolChoiceActive(params)) {
|
|
2346
4047
|
return toolChoiceStream({
|
|
2347
4048
|
doGenerate,
|
|
2348
|
-
|
|
4049
|
+
tools,
|
|
4050
|
+
options: onErrorOptions
|
|
2349
4051
|
});
|
|
2350
4052
|
}
|
|
2351
4053
|
const { stream, ...rest } = await doStream();
|
|
2352
4054
|
const debugLevel = getDebugLevel();
|
|
2353
|
-
const tools = originalToolsSchema.decode(
|
|
2354
|
-
(_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
|
|
2355
|
-
);
|
|
2356
4055
|
const options = {
|
|
2357
|
-
...
|
|
4056
|
+
...onErrorOptions,
|
|
2358
4057
|
...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
|
|
2359
4058
|
};
|
|
2360
4059
|
const coreStream = stream.pipeThrough(
|
|
@@ -2369,13 +4068,26 @@ async function wrapStream({
|
|
|
2369
4068
|
}
|
|
2370
4069
|
)
|
|
2371
4070
|
).pipeThrough(protocol.createStreamParser({ tools, options }));
|
|
4071
|
+
let seenToolCall = false;
|
|
2372
4072
|
const v3Stream = coreStream.pipeThrough(
|
|
2373
4073
|
new TransformStream({
|
|
2374
4074
|
transform(part, controller) {
|
|
4075
|
+
let normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
|
|
4076
|
+
if (normalizedPart.type === "tool-call") {
|
|
4077
|
+
seenToolCall = true;
|
|
4078
|
+
}
|
|
4079
|
+
if (normalizedPart.type === "finish" && seenToolCall && normalizedPart.finishReason.unified === "stop") {
|
|
4080
|
+
normalizedPart = {
|
|
4081
|
+
...normalizedPart,
|
|
4082
|
+
finishReason: normalizeToolCallsFinishReason(
|
|
4083
|
+
normalizedPart.finishReason
|
|
4084
|
+
)
|
|
4085
|
+
};
|
|
4086
|
+
}
|
|
2375
4087
|
if (debugLevel === "stream") {
|
|
2376
|
-
logParsedChunk(
|
|
4088
|
+
logParsedChunk(normalizedPart);
|
|
2377
4089
|
}
|
|
2378
|
-
controller.enqueue(
|
|
4090
|
+
controller.enqueue(normalizedPart);
|
|
2379
4091
|
}
|
|
2380
4092
|
})
|
|
2381
4093
|
);
|
|
@@ -2386,41 +4098,36 @@ async function wrapStream({
|
|
|
2386
4098
|
}
|
|
2387
4099
|
async function toolChoiceStream({
|
|
2388
4100
|
doGenerate,
|
|
4101
|
+
tools,
|
|
2389
4102
|
options
|
|
2390
4103
|
}) {
|
|
2391
|
-
var _a
|
|
4104
|
+
var _a;
|
|
4105
|
+
const normalizedTools = Array.isArray(tools) ? tools : [];
|
|
2392
4106
|
const result = await doGenerate();
|
|
2393
|
-
let
|
|
4107
|
+
let toolName = "unknown";
|
|
4108
|
+
let input = "{}";
|
|
2394
4109
|
if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2404
|
-
}
|
|
2405
|
-
);
|
|
2406
|
-
toolJson = {};
|
|
2407
|
-
}
|
|
4110
|
+
const parsed = parseToolChoicePayload({
|
|
4111
|
+
text: result.content[0].text,
|
|
4112
|
+
tools: normalizedTools,
|
|
4113
|
+
onError: options == null ? void 0 : options.onError,
|
|
4114
|
+
errorMessage: "Failed to parse toolChoice JSON from streamed model output"
|
|
4115
|
+
});
|
|
4116
|
+
toolName = parsed.toolName;
|
|
4117
|
+
input = parsed.input;
|
|
2408
4118
|
}
|
|
2409
4119
|
const stream = new ReadableStream({
|
|
2410
4120
|
start(controller) {
|
|
2411
4121
|
controller.enqueue({
|
|
2412
4122
|
type: "tool-call",
|
|
2413
|
-
toolCallId:
|
|
2414
|
-
toolName
|
|
2415
|
-
input
|
|
4123
|
+
toolCallId: generateToolCallId(),
|
|
4124
|
+
toolName,
|
|
4125
|
+
input
|
|
2416
4126
|
});
|
|
2417
4127
|
controller.enqueue({
|
|
2418
4128
|
type: "finish",
|
|
2419
|
-
usage: (result == null ? void 0 : result.usage)
|
|
2420
|
-
|
|
2421
|
-
outputTokens: 0
|
|
2422
|
-
},
|
|
2423
|
-
finishReason: "tool-calls"
|
|
4129
|
+
usage: normalizeUsage(result == null ? void 0 : result.usage),
|
|
4130
|
+
finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
|
|
2424
4131
|
});
|
|
2425
4132
|
controller.close();
|
|
2426
4133
|
}
|
|
@@ -2431,6 +4138,60 @@ async function toolChoiceStream({
|
|
|
2431
4138
|
stream
|
|
2432
4139
|
};
|
|
2433
4140
|
}
|
|
4141
|
+
var ZERO_USAGE = {
|
|
4142
|
+
inputTokens: {
|
|
4143
|
+
total: 0,
|
|
4144
|
+
noCache: void 0,
|
|
4145
|
+
cacheRead: void 0,
|
|
4146
|
+
cacheWrite: void 0
|
|
4147
|
+
},
|
|
4148
|
+
outputTokens: {
|
|
4149
|
+
total: 0,
|
|
4150
|
+
text: void 0,
|
|
4151
|
+
reasoning: void 0
|
|
4152
|
+
}
|
|
4153
|
+
};
|
|
4154
|
+
function normalizeToolCallsFinishReason(finishReason) {
|
|
4155
|
+
let raw = "tool-calls";
|
|
4156
|
+
if (typeof finishReason === "string") {
|
|
4157
|
+
raw = finishReason;
|
|
4158
|
+
} else if (finishReason && typeof finishReason === "object" && "raw" in finishReason && typeof finishReason.raw === "string") {
|
|
4159
|
+
raw = finishReason.raw;
|
|
4160
|
+
} else if (finishReason && typeof finishReason === "object" && "unified" in finishReason && typeof finishReason.unified === "string") {
|
|
4161
|
+
raw = finishReason.unified;
|
|
4162
|
+
}
|
|
4163
|
+
return {
|
|
4164
|
+
unified: "tool-calls",
|
|
4165
|
+
raw
|
|
4166
|
+
};
|
|
4167
|
+
}
|
|
4168
|
+
function normalizeUsage(usage) {
|
|
4169
|
+
if (!usage || typeof usage !== "object") {
|
|
4170
|
+
return ZERO_USAGE;
|
|
4171
|
+
}
|
|
4172
|
+
const usageRecord = usage;
|
|
4173
|
+
const input = usageRecord.inputTokens;
|
|
4174
|
+
const output = usageRecord.outputTokens;
|
|
4175
|
+
if (input && typeof input === "object" && output && typeof output === "object") {
|
|
4176
|
+
return usage;
|
|
4177
|
+
}
|
|
4178
|
+
if (typeof input === "number" && typeof output === "number") {
|
|
4179
|
+
return {
|
|
4180
|
+
inputTokens: {
|
|
4181
|
+
total: input,
|
|
4182
|
+
noCache: void 0,
|
|
4183
|
+
cacheRead: void 0,
|
|
4184
|
+
cacheWrite: void 0
|
|
4185
|
+
},
|
|
4186
|
+
outputTokens: {
|
|
4187
|
+
total: output,
|
|
4188
|
+
text: void 0,
|
|
4189
|
+
reasoning: void 0
|
|
4190
|
+
}
|
|
4191
|
+
};
|
|
4192
|
+
}
|
|
4193
|
+
return ZERO_USAGE;
|
|
4194
|
+
}
|
|
2434
4195
|
|
|
2435
4196
|
// src/transform-handler.ts
|
|
2436
4197
|
function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
|
|
@@ -2556,6 +4317,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
|
|
|
2556
4317
|
"Tool choice type 'required' is set, but no tools are provided in params.tools."
|
|
2557
4318
|
);
|
|
2558
4319
|
}
|
|
4320
|
+
if (functionTools.length === 0) {
|
|
4321
|
+
throw new Error(
|
|
4322
|
+
"Tool choice type 'required' is set, but no function tools are provided. Provider-defined tools are not supported by this middleware."
|
|
4323
|
+
);
|
|
4324
|
+
}
|
|
2559
4325
|
return {
|
|
2560
4326
|
...baseReturnParams,
|
|
2561
4327
|
responseFormat: {
|
|
@@ -2866,4 +4632,4 @@ export {
|
|
|
2866
4632
|
xmlToolMiddleware,
|
|
2867
4633
|
yamlToolMiddleware
|
|
2868
4634
|
};
|
|
2869
|
-
//# sourceMappingURL=chunk-
|
|
4635
|
+
//# sourceMappingURL=chunk-ERJKQKCR.js.map
|