@ai-sdk-tool/parser 3.3.3 → 4.0.1
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-CXWS24JX.js → chunk-76E6H46R.js} +2 -2
- package/dist/{chunk-2KK5BDZF.js → chunk-DJB4DAZO.js} +23 -6
- package/dist/chunk-DJB4DAZO.js.map +1 -0
- package/dist/{chunk-NAQSTPDQ.js → chunk-DPGORNPB.js} +1388 -211
- package/dist/chunk-DPGORNPB.js.map +1 -0
- package/dist/community.cjs +1420 -226
- package/dist/community.cjs.map +1 -1
- package/dist/community.js +3 -3
- package/dist/index.cjs +1420 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +3 -3
- package/dist/rxml.cjs +22 -5
- package/dist/rxml.cjs.map +1 -1
- package/dist/rxml.js +2 -2
- package/dist/schema-coerce.cjs +22 -5
- package/dist/schema-coerce.cjs.map +1 -1
- package/dist/schema-coerce.js +1 -1
- package/package.json +7 -7
- package/dist/chunk-2KK5BDZF.js.map +0 -1
- package/dist/chunk-NAQSTPDQ.js.map +0 -1
- /package/dist/{chunk-CXWS24JX.js.map → chunk-76E6H46R.js.map} +0 -0
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
escapeRegExp,
|
|
3
3
|
parse as parse2,
|
|
4
4
|
stringify
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-76E6H46R.js";
|
|
6
6
|
import {
|
|
7
7
|
parse
|
|
8
8
|
} from "./chunk-IX4FJELL.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
coerceBySchema,
|
|
11
11
|
getSchemaType,
|
|
12
12
|
unwrapJsonSchema
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DJB4DAZO.js";
|
|
14
14
|
|
|
15
15
|
// src/core/utils/debug.ts
|
|
16
16
|
var LINE_SPLIT_REGEX = /\r?\n/;
|
|
@@ -176,9 +176,19 @@ function getPotentialStartIndex(text, searchedText) {
|
|
|
176
176
|
if (directIndex !== -1) {
|
|
177
177
|
return directIndex;
|
|
178
178
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
const textLength = text.length;
|
|
180
|
+
const searchedTextLength = searchedText.length;
|
|
181
|
+
const startAt = Math.max(0, textLength - searchedTextLength + 1);
|
|
182
|
+
for (let i = startAt; i < textLength; i++) {
|
|
183
|
+
let match = true;
|
|
184
|
+
const currentSuffixLength = textLength - i;
|
|
185
|
+
for (let j = 0; j < currentSuffixLength; j++) {
|
|
186
|
+
if (text[i + j] !== searchedText[j]) {
|
|
187
|
+
match = false;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (match) {
|
|
182
192
|
return i;
|
|
183
193
|
}
|
|
184
194
|
}
|
|
@@ -187,7 +197,25 @@ function getPotentialStartIndex(text, searchedText) {
|
|
|
187
197
|
|
|
188
198
|
// src/core/utils/id.ts
|
|
189
199
|
function generateId() {
|
|
190
|
-
return
|
|
200
|
+
return crypto.randomUUID().replace(/-/g, "").slice(0, 13);
|
|
201
|
+
}
|
|
202
|
+
var TOOL_CALL_ID_PREFIX = "call_";
|
|
203
|
+
var TOOL_CALL_ID_BODY_LENGTH = 24;
|
|
204
|
+
var TOOL_CALL_ID_ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
205
|
+
function randomAlphaNumeric(length) {
|
|
206
|
+
var _a;
|
|
207
|
+
const bytes = new Uint8Array(length);
|
|
208
|
+
crypto.getRandomValues(bytes);
|
|
209
|
+
let out = "";
|
|
210
|
+
for (let i = 0; i < length; i += 1) {
|
|
211
|
+
const byte = bytes[i];
|
|
212
|
+
const index = (byte != null ? byte : 0) % TOOL_CALL_ID_ALPHANUM.length;
|
|
213
|
+
out += (_a = TOOL_CALL_ID_ALPHANUM[index]) != null ? _a : "0";
|
|
214
|
+
}
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
function generateToolCallId() {
|
|
218
|
+
return `${TOOL_CALL_ID_PREFIX}${randomAlphaNumeric(TOOL_CALL_ID_BODY_LENGTH)}`;
|
|
191
219
|
}
|
|
192
220
|
|
|
193
221
|
// src/core/utils/protocol-utils.ts
|
|
@@ -196,17 +224,55 @@ function addTextSegment(text, processedElements) {
|
|
|
196
224
|
processedElements.push({ type: "text", text });
|
|
197
225
|
}
|
|
198
226
|
}
|
|
227
|
+
function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
228
|
+
return (controller, text) => {
|
|
229
|
+
const content = text;
|
|
230
|
+
if (content) {
|
|
231
|
+
if (!getCurrentTextId()) {
|
|
232
|
+
const newId = generateId();
|
|
233
|
+
setCurrentTextId(newId);
|
|
234
|
+
controller.enqueue({
|
|
235
|
+
type: "text-start",
|
|
236
|
+
id: newId
|
|
237
|
+
});
|
|
238
|
+
setHasEmittedTextStart(true);
|
|
239
|
+
}
|
|
240
|
+
controller.enqueue({
|
|
241
|
+
type: "text-delta",
|
|
242
|
+
id: getCurrentTextId(),
|
|
243
|
+
delta: content
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
const currentTextId = getCurrentTextId();
|
|
247
|
+
if (currentTextId && !text) {
|
|
248
|
+
if (getHasEmittedTextStart()) {
|
|
249
|
+
controller.enqueue({
|
|
250
|
+
type: "text-end",
|
|
251
|
+
id: currentTextId
|
|
252
|
+
});
|
|
253
|
+
setHasEmittedTextStart(false);
|
|
254
|
+
}
|
|
255
|
+
setCurrentTextId(null);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
199
259
|
|
|
200
260
|
// src/core/protocols/json-protocol.ts
|
|
261
|
+
function shouldEmitRawToolCallTextOnError(options) {
|
|
262
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
263
|
+
}
|
|
264
|
+
function canonicalizeToolInput(argumentsValue) {
|
|
265
|
+
return JSON.stringify(argumentsValue != null ? argumentsValue : {});
|
|
266
|
+
}
|
|
201
267
|
function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
|
|
202
|
-
var _a
|
|
268
|
+
var _a;
|
|
203
269
|
try {
|
|
204
270
|
const parsedToolCall = parse(toolCallJson);
|
|
205
271
|
processedElements.push({
|
|
206
272
|
type: "tool-call",
|
|
207
|
-
toolCallId:
|
|
273
|
+
toolCallId: generateToolCallId(),
|
|
208
274
|
toolName: parsedToolCall.name,
|
|
209
|
-
input:
|
|
275
|
+
input: canonicalizeToolInput(parsedToolCall.arguments)
|
|
210
276
|
});
|
|
211
277
|
} catch (error) {
|
|
212
278
|
logParseFailure({
|
|
@@ -215,7 +281,7 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
|
|
|
215
281
|
snippet: fullMatch,
|
|
216
282
|
error
|
|
217
283
|
});
|
|
218
|
-
(
|
|
284
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
219
285
|
options,
|
|
220
286
|
"Could not process JSON tool call, keeping original text.",
|
|
221
287
|
{ toolCall: fullMatch, error }
|
|
@@ -236,6 +302,293 @@ function processMatchedToolCall(context) {
|
|
|
236
302
|
}
|
|
237
303
|
return startIndex + match[0].length;
|
|
238
304
|
}
|
|
305
|
+
var WHITESPACE_JSON_REGEX = /\s/;
|
|
306
|
+
function skipJsonWhitespace(text, fromIndex) {
|
|
307
|
+
let index = fromIndex;
|
|
308
|
+
while (index < text.length && WHITESPACE_JSON_REGEX.test(text[index])) {
|
|
309
|
+
index += 1;
|
|
310
|
+
}
|
|
311
|
+
return index;
|
|
312
|
+
}
|
|
313
|
+
function findTopLevelPropertyValueStart(text, property) {
|
|
314
|
+
const objectStart = skipJsonWhitespace(text, 0);
|
|
315
|
+
if (objectStart >= text.length || text.charAt(objectStart) !== "{") {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
let depth = 0;
|
|
319
|
+
let inString = false;
|
|
320
|
+
let escaping = false;
|
|
321
|
+
for (let index = objectStart; index < text.length; index += 1) {
|
|
322
|
+
const char = text.charAt(index);
|
|
323
|
+
if (inString) {
|
|
324
|
+
if (escaping) {
|
|
325
|
+
escaping = false;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (char === "\\") {
|
|
329
|
+
escaping = true;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (char === '"') {
|
|
333
|
+
inString = false;
|
|
334
|
+
}
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (char === "{") {
|
|
338
|
+
depth += 1;
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (char === "}") {
|
|
342
|
+
depth = Math.max(0, depth - 1);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (char !== '"') {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (depth !== 1) {
|
|
349
|
+
inString = true;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const keyStart = index + 1;
|
|
353
|
+
let keyEnd = keyStart;
|
|
354
|
+
let keyEscaped = false;
|
|
355
|
+
while (keyEnd < text.length) {
|
|
356
|
+
const keyChar = text.charAt(keyEnd);
|
|
357
|
+
if (keyEscaped) {
|
|
358
|
+
keyEscaped = false;
|
|
359
|
+
} else if (keyChar === "\\") {
|
|
360
|
+
keyEscaped = true;
|
|
361
|
+
} else if (keyChar === '"') {
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
keyEnd += 1;
|
|
365
|
+
}
|
|
366
|
+
if (keyEnd >= text.length || text.charAt(keyEnd) !== '"') {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
const key = text.slice(keyStart, keyEnd);
|
|
370
|
+
let valueCursor = skipJsonWhitespace(text, keyEnd + 1);
|
|
371
|
+
if (valueCursor >= text.length || text.charAt(valueCursor) !== ":") {
|
|
372
|
+
index = keyEnd;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
valueCursor = skipJsonWhitespace(text, valueCursor + 1);
|
|
376
|
+
if (key === property) {
|
|
377
|
+
return valueCursor < text.length ? valueCursor : null;
|
|
378
|
+
}
|
|
379
|
+
index = valueCursor - 1;
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
function extractTopLevelStringProperty(text, property) {
|
|
384
|
+
const valueStart = findTopLevelPropertyValueStart(text, property);
|
|
385
|
+
if (valueStart == null || valueStart >= text.length) {
|
|
386
|
+
return void 0;
|
|
387
|
+
}
|
|
388
|
+
if (text.charAt(valueStart) !== '"') {
|
|
389
|
+
return void 0;
|
|
390
|
+
}
|
|
391
|
+
let valueEnd = valueStart + 1;
|
|
392
|
+
let escaped = false;
|
|
393
|
+
while (valueEnd < text.length) {
|
|
394
|
+
const char = text.charAt(valueEnd);
|
|
395
|
+
if (escaped) {
|
|
396
|
+
escaped = false;
|
|
397
|
+
} else if (char === "\\") {
|
|
398
|
+
escaped = true;
|
|
399
|
+
} else if (char === '"') {
|
|
400
|
+
return text.slice(valueStart + 1, valueEnd);
|
|
401
|
+
}
|
|
402
|
+
valueEnd += 1;
|
|
403
|
+
}
|
|
404
|
+
return void 0;
|
|
405
|
+
}
|
|
406
|
+
function extractJsonValueSlice(text, valueStart) {
|
|
407
|
+
if (valueStart >= text.length) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
const first = text.charAt(valueStart);
|
|
411
|
+
if (first === "{" || first === "[") {
|
|
412
|
+
const stack = [first];
|
|
413
|
+
let inString = false;
|
|
414
|
+
let escaped = false;
|
|
415
|
+
for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
|
|
416
|
+
const char = text.charAt(index2);
|
|
417
|
+
if (inString) {
|
|
418
|
+
if (escaped) {
|
|
419
|
+
escaped = false;
|
|
420
|
+
} else if (char === "\\") {
|
|
421
|
+
escaped = true;
|
|
422
|
+
} else if (char === '"') {
|
|
423
|
+
inString = false;
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (char === '"') {
|
|
428
|
+
inString = true;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (char === "{" || char === "[") {
|
|
432
|
+
stack.push(char);
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (char === "}" || char === "]") {
|
|
436
|
+
const open = stack.at(-1);
|
|
437
|
+
if (open === "{" && char === "}" || open === "[" && char === "]") {
|
|
438
|
+
stack.pop();
|
|
439
|
+
if (stack.length === 0) {
|
|
440
|
+
return {
|
|
441
|
+
text: text.slice(valueStart, index2 + 1),
|
|
442
|
+
complete: true
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
text: text.slice(valueStart),
|
|
450
|
+
complete: false
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (first === '"') {
|
|
454
|
+
let escaped = false;
|
|
455
|
+
for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
|
|
456
|
+
const char = text.charAt(index2);
|
|
457
|
+
if (escaped) {
|
|
458
|
+
escaped = false;
|
|
459
|
+
} else if (char === "\\") {
|
|
460
|
+
escaped = true;
|
|
461
|
+
} else if (char === '"') {
|
|
462
|
+
return {
|
|
463
|
+
text: text.slice(valueStart, index2 + 1),
|
|
464
|
+
complete: true
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
text: text.slice(valueStart),
|
|
470
|
+
complete: false
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
let index = valueStart;
|
|
474
|
+
while (index < text.length) {
|
|
475
|
+
const char = text.charAt(index);
|
|
476
|
+
if (char === "," || char === "}" || WHITESPACE_JSON_REGEX.test(char)) {
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
index += 1;
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
text: text.slice(valueStart, index),
|
|
483
|
+
complete: index < text.length
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function extractStreamingToolCallProgress(toolCallJson) {
|
|
487
|
+
var _a;
|
|
488
|
+
const toolName = extractTopLevelStringProperty(toolCallJson, "name");
|
|
489
|
+
const argsValueStart = findTopLevelPropertyValueStart(
|
|
490
|
+
toolCallJson,
|
|
491
|
+
"arguments"
|
|
492
|
+
);
|
|
493
|
+
if (argsValueStart == null) {
|
|
494
|
+
return {
|
|
495
|
+
toolName,
|
|
496
|
+
argumentsText: void 0,
|
|
497
|
+
argumentsComplete: false
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
const argsSlice = extractJsonValueSlice(toolCallJson, argsValueStart);
|
|
501
|
+
return {
|
|
502
|
+
toolName,
|
|
503
|
+
argumentsText: argsSlice == null ? void 0 : argsSlice.text,
|
|
504
|
+
argumentsComplete: (_a = argsSlice == null ? void 0 : argsSlice.complete) != null ? _a : false
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function ensureToolInputStart(state, controller, toolName) {
|
|
508
|
+
if (!state.activeToolInput) {
|
|
509
|
+
const id = generateToolCallId();
|
|
510
|
+
state.activeToolInput = {
|
|
511
|
+
id,
|
|
512
|
+
toolName,
|
|
513
|
+
emittedInput: ""
|
|
514
|
+
};
|
|
515
|
+
controller.enqueue({
|
|
516
|
+
type: "tool-input-start",
|
|
517
|
+
id,
|
|
518
|
+
toolName
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function emitToolInputDelta(state, controller, fullInput) {
|
|
523
|
+
const active = state.activeToolInput;
|
|
524
|
+
if (!active) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (!fullInput.startsWith(active.emittedInput)) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const delta = fullInput.slice(active.emittedInput.length);
|
|
531
|
+
if (delta.length === 0) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
controller.enqueue({
|
|
535
|
+
type: "tool-input-delta",
|
|
536
|
+
id: active.id,
|
|
537
|
+
delta
|
|
538
|
+
});
|
|
539
|
+
active.emittedInput = fullInput;
|
|
540
|
+
}
|
|
541
|
+
function closeToolInput(state, controller) {
|
|
542
|
+
if (!state.activeToolInput) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
controller.enqueue({
|
|
546
|
+
type: "tool-input-end",
|
|
547
|
+
id: state.activeToolInput.id
|
|
548
|
+
});
|
|
549
|
+
state.activeToolInput = null;
|
|
550
|
+
}
|
|
551
|
+
function emitToolCallFromParsed(state, controller, parsedToolCall) {
|
|
552
|
+
var _a, _b, _c, _d;
|
|
553
|
+
closeTextBlock(state, controller);
|
|
554
|
+
const toolName = typeof parsedToolCall.name === "string" ? parsedToolCall.name : (_b = (_a = state.activeToolInput) == null ? void 0 : _a.toolName) != null ? _b : "unknown";
|
|
555
|
+
const input = canonicalizeToolInput(parsedToolCall.arguments);
|
|
556
|
+
ensureToolInputStart(state, controller, toolName);
|
|
557
|
+
emitToolInputDelta(state, controller, input);
|
|
558
|
+
const toolCallId = (_d = (_c = state.activeToolInput) == null ? void 0 : _c.id) != null ? _d : generateToolCallId();
|
|
559
|
+
closeToolInput(state, controller);
|
|
560
|
+
controller.enqueue({
|
|
561
|
+
type: "tool-call",
|
|
562
|
+
toolCallId,
|
|
563
|
+
toolName,
|
|
564
|
+
input
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
function canonicalizeArgumentsProgressInput(progress) {
|
|
568
|
+
if (progress.argumentsText === void 0 || !progress.argumentsComplete) {
|
|
569
|
+
return void 0;
|
|
570
|
+
}
|
|
571
|
+
try {
|
|
572
|
+
const parsedArguments = parse(progress.argumentsText);
|
|
573
|
+
return canonicalizeToolInput(parsedArguments);
|
|
574
|
+
} catch (e) {
|
|
575
|
+
return void 0;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function emitToolInputProgress(state, controller) {
|
|
579
|
+
if (!(state.isInsideToolCall && state.currentToolCallJson)) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const progress = extractStreamingToolCallProgress(state.currentToolCallJson);
|
|
583
|
+
if (!progress.toolName) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
ensureToolInputStart(state, controller, progress.toolName);
|
|
587
|
+
const canonicalProgressInput = canonicalizeArgumentsProgressInput(progress);
|
|
588
|
+
if (canonicalProgressInput !== void 0) {
|
|
589
|
+
emitToolInputDelta(state, controller, canonicalProgressInput);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
239
592
|
function flushBuffer(state, controller, toolCallStart) {
|
|
240
593
|
if (state.buffer.length === 0) {
|
|
241
594
|
return;
|
|
@@ -266,44 +619,77 @@ function closeTextBlock(state, controller) {
|
|
|
266
619
|
state.hasEmittedTextStart = false;
|
|
267
620
|
}
|
|
268
621
|
}
|
|
269
|
-
function emitIncompleteToolCall(state, controller, toolCallStart) {
|
|
270
|
-
|
|
622
|
+
function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, options) {
|
|
623
|
+
var _a;
|
|
624
|
+
if (!state.currentToolCallJson && trailingBuffer.length === 0) {
|
|
625
|
+
state.isInsideToolCall = false;
|
|
271
626
|
return;
|
|
272
627
|
}
|
|
628
|
+
if (state.currentToolCallJson) {
|
|
629
|
+
try {
|
|
630
|
+
const parsedToolCall = parse(state.currentToolCallJson);
|
|
631
|
+
emitToolCallFromParsed(state, controller, parsedToolCall);
|
|
632
|
+
state.currentToolCallJson = "";
|
|
633
|
+
state.isInsideToolCall = false;
|
|
634
|
+
return;
|
|
635
|
+
} catch (e) {
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
const rawToolCallContent = `${state.currentToolCallJson}${trailingBuffer}`;
|
|
639
|
+
const errorContent = `${toolCallStart}${rawToolCallContent}`;
|
|
640
|
+
const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
|
|
273
641
|
logParseFailure({
|
|
274
642
|
phase: "stream",
|
|
275
|
-
reason: "Incomplete streaming tool call segment emitted as text",
|
|
276
|
-
snippet:
|
|
277
|
-
});
|
|
278
|
-
const errorId = generateId();
|
|
279
|
-
const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
|
|
280
|
-
controller.enqueue({
|
|
281
|
-
type: "text-start",
|
|
282
|
-
id: errorId
|
|
283
|
-
});
|
|
284
|
-
controller.enqueue({
|
|
285
|
-
type: "text-delta",
|
|
286
|
-
id: errorId,
|
|
287
|
-
delta: errorContent
|
|
288
|
-
});
|
|
289
|
-
controller.enqueue({
|
|
290
|
-
type: "text-end",
|
|
291
|
-
id: errorId
|
|
643
|
+
reason: shouldEmitRawFallback ? "Incomplete streaming tool call segment emitted as text" : "Incomplete streaming tool call segment suppressed without raw text fallback",
|
|
644
|
+
snippet: errorContent
|
|
292
645
|
});
|
|
646
|
+
if (shouldEmitRawFallback) {
|
|
647
|
+
const errorId = generateId();
|
|
648
|
+
controller.enqueue({
|
|
649
|
+
type: "text-start",
|
|
650
|
+
id: errorId
|
|
651
|
+
});
|
|
652
|
+
controller.enqueue({
|
|
653
|
+
type: "text-delta",
|
|
654
|
+
id: errorId,
|
|
655
|
+
delta: errorContent
|
|
656
|
+
});
|
|
657
|
+
controller.enqueue({
|
|
658
|
+
type: "text-end",
|
|
659
|
+
id: errorId
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
closeToolInput(state, controller);
|
|
663
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
664
|
+
options,
|
|
665
|
+
shouldEmitRawFallback ? "Could not complete streaming JSON tool call at finish; emitting original text." : "Could not complete streaming JSON tool call at finish.",
|
|
666
|
+
{ toolCall: errorContent }
|
|
667
|
+
);
|
|
293
668
|
state.currentToolCallJson = "";
|
|
669
|
+
state.isInsideToolCall = false;
|
|
294
670
|
}
|
|
295
|
-
function handleFinishChunk(state, controller, toolCallStart, chunk) {
|
|
296
|
-
if (state.
|
|
671
|
+
function handleFinishChunk(state, controller, toolCallStart, options, chunk) {
|
|
672
|
+
if (state.isInsideToolCall) {
|
|
673
|
+
const trailingBuffer = state.buffer;
|
|
674
|
+
state.buffer = "";
|
|
675
|
+
emitIncompleteToolCall(
|
|
676
|
+
state,
|
|
677
|
+
controller,
|
|
678
|
+
toolCallStart,
|
|
679
|
+
trailingBuffer,
|
|
680
|
+
options
|
|
681
|
+
);
|
|
682
|
+
} else if (state.buffer.length > 0) {
|
|
297
683
|
flushBuffer(state, controller, toolCallStart);
|
|
298
684
|
}
|
|
299
685
|
closeTextBlock(state, controller);
|
|
300
|
-
emitIncompleteToolCall(state, controller, toolCallStart);
|
|
301
686
|
controller.enqueue(chunk);
|
|
302
687
|
}
|
|
303
688
|
function publishText(text, state, controller) {
|
|
304
689
|
if (state.isInsideToolCall) {
|
|
305
690
|
closeTextBlock(state, controller);
|
|
306
691
|
state.currentToolCallJson += text;
|
|
692
|
+
emitToolInputProgress(state, controller);
|
|
307
693
|
} else if (text.length > 0) {
|
|
308
694
|
if (!state.currentTextId) {
|
|
309
695
|
state.currentTextId = generateId();
|
|
@@ -321,42 +707,40 @@ function publishText(text, state, controller) {
|
|
|
321
707
|
}
|
|
322
708
|
}
|
|
323
709
|
function emitToolCall(context) {
|
|
324
|
-
var _a
|
|
710
|
+
var _a;
|
|
325
711
|
const { state, controller, toolCallStart, toolCallEnd, options } = context;
|
|
326
712
|
try {
|
|
327
713
|
const parsedToolCall = parse(state.currentToolCallJson);
|
|
328
|
-
|
|
329
|
-
controller.enqueue({
|
|
330
|
-
type: "tool-call",
|
|
331
|
-
toolCallId: generateId(),
|
|
332
|
-
toolName: parsedToolCall.name,
|
|
333
|
-
input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
|
|
334
|
-
});
|
|
714
|
+
emitToolCallFromParsed(state, controller, parsedToolCall);
|
|
335
715
|
} catch (error) {
|
|
716
|
+
const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
|
|
717
|
+
const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
|
|
336
718
|
logParseFailure({
|
|
337
719
|
phase: "stream",
|
|
338
720
|
reason: "Failed to parse streaming tool call JSON segment",
|
|
339
|
-
snippet:
|
|
721
|
+
snippet: errorContent,
|
|
340
722
|
error
|
|
341
723
|
});
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
724
|
+
if (shouldEmitRawFallback) {
|
|
725
|
+
const errorId = generateId();
|
|
726
|
+
controller.enqueue({
|
|
727
|
+
type: "text-start",
|
|
728
|
+
id: errorId
|
|
729
|
+
});
|
|
730
|
+
controller.enqueue({
|
|
731
|
+
type: "text-delta",
|
|
732
|
+
id: errorId,
|
|
733
|
+
delta: errorContent
|
|
734
|
+
});
|
|
735
|
+
controller.enqueue({
|
|
736
|
+
type: "text-end",
|
|
737
|
+
id: errorId
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
closeToolInput(state, controller);
|
|
741
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
358
742
|
options,
|
|
359
|
-
"Could not process streaming JSON tool call; emitting original text.",
|
|
743
|
+
shouldEmitRawFallback ? "Could not process streaming JSON tool call; emitting original text." : "Could not process streaming JSON tool call.",
|
|
360
744
|
{
|
|
361
745
|
toolCall: errorContent
|
|
362
746
|
}
|
|
@@ -372,6 +756,7 @@ function processTagMatch(context) {
|
|
|
372
756
|
} else {
|
|
373
757
|
state.currentToolCallJson = "";
|
|
374
758
|
state.isInsideToolCall = true;
|
|
759
|
+
state.activeToolInput = null;
|
|
375
760
|
}
|
|
376
761
|
}
|
|
377
762
|
function processBufferTags(context) {
|
|
@@ -394,8 +779,16 @@ function processBufferTags(context) {
|
|
|
394
779
|
);
|
|
395
780
|
}
|
|
396
781
|
}
|
|
397
|
-
function handlePartialTag(state, controller, toolCallStart) {
|
|
782
|
+
function handlePartialTag(state, controller, toolCallStart, toolCallEnd) {
|
|
398
783
|
if (state.isInsideToolCall) {
|
|
784
|
+
const potentialEndIndex = getPotentialStartIndex(state.buffer, toolCallEnd);
|
|
785
|
+
if (potentialEndIndex != null && potentialEndIndex + toolCallEnd.length > state.buffer.length) {
|
|
786
|
+
publishText(state.buffer.slice(0, potentialEndIndex), state, controller);
|
|
787
|
+
state.buffer = state.buffer.slice(potentialEndIndex);
|
|
788
|
+
} else {
|
|
789
|
+
publishText(state.buffer, state, controller);
|
|
790
|
+
state.buffer = "";
|
|
791
|
+
}
|
|
399
792
|
return;
|
|
400
793
|
}
|
|
401
794
|
const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
|
|
@@ -468,13 +861,14 @@ var jsonProtocol = ({
|
|
|
468
861
|
buffer: "",
|
|
469
862
|
currentToolCallJson: "",
|
|
470
863
|
currentTextId: null,
|
|
471
|
-
hasEmittedTextStart: false
|
|
864
|
+
hasEmittedTextStart: false,
|
|
865
|
+
activeToolInput: null
|
|
472
866
|
};
|
|
473
867
|
return new TransformStream({
|
|
474
868
|
transform(chunk, controller) {
|
|
475
869
|
var _a;
|
|
476
870
|
if (chunk.type === "finish") {
|
|
477
|
-
handleFinishChunk(state, controller, toolCallStart, chunk);
|
|
871
|
+
handleFinishChunk(state, controller, toolCallStart, options, chunk);
|
|
478
872
|
return;
|
|
479
873
|
}
|
|
480
874
|
if (chunk.type !== "text-delta") {
|
|
@@ -490,7 +884,7 @@ var jsonProtocol = ({
|
|
|
490
884
|
toolCallEnd,
|
|
491
885
|
options
|
|
492
886
|
});
|
|
493
|
-
handlePartialTag(state, controller, toolCallStart);
|
|
887
|
+
handlePartialTag(state, controller, toolCallStart, toolCallEnd);
|
|
494
888
|
}
|
|
495
889
|
});
|
|
496
890
|
},
|
|
@@ -520,6 +914,80 @@ function isTCMProtocolFactory(protocol) {
|
|
|
520
914
|
var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
|
|
521
915
|
var WHITESPACE_REGEX = /\s/;
|
|
522
916
|
|
|
917
|
+
// src/core/utils/streamed-tool-input-delta.ts
|
|
918
|
+
function emitDelta({
|
|
919
|
+
controller,
|
|
920
|
+
id,
|
|
921
|
+
state,
|
|
922
|
+
nextInput
|
|
923
|
+
}) {
|
|
924
|
+
if (!nextInput.startsWith(state.emittedInput)) {
|
|
925
|
+
return false;
|
|
926
|
+
}
|
|
927
|
+
const delta = nextInput.slice(state.emittedInput.length);
|
|
928
|
+
if (delta.length === 0) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
controller.enqueue({
|
|
932
|
+
type: "tool-input-delta",
|
|
933
|
+
id,
|
|
934
|
+
delta
|
|
935
|
+
});
|
|
936
|
+
state.emittedInput = nextInput;
|
|
937
|
+
return true;
|
|
938
|
+
}
|
|
939
|
+
function toIncompleteJsonPrefix(fullJson) {
|
|
940
|
+
const trimmed = fullJson.trim();
|
|
941
|
+
let prefix = trimmed;
|
|
942
|
+
while (prefix.endsWith("}") || prefix.endsWith("]")) {
|
|
943
|
+
prefix = prefix.slice(0, -1);
|
|
944
|
+
}
|
|
945
|
+
prefix = prefix.trimEnd();
|
|
946
|
+
if (prefix.endsWith('"')) {
|
|
947
|
+
prefix = prefix.slice(0, -1);
|
|
948
|
+
}
|
|
949
|
+
if (prefix.length === 0) {
|
|
950
|
+
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
|
|
951
|
+
return trimmed.startsWith("{") ? "{" : "[";
|
|
952
|
+
}
|
|
953
|
+
if (trimmed.startsWith("]")) {
|
|
954
|
+
return "[";
|
|
955
|
+
}
|
|
956
|
+
if (trimmed.startsWith("}")) {
|
|
957
|
+
return "{";
|
|
958
|
+
}
|
|
959
|
+
if (trimmed.startsWith('"')) {
|
|
960
|
+
return '"';
|
|
961
|
+
}
|
|
962
|
+
return "{";
|
|
963
|
+
}
|
|
964
|
+
return prefix;
|
|
965
|
+
}
|
|
966
|
+
function emitPrefixDelta(params) {
|
|
967
|
+
return emitDelta({
|
|
968
|
+
...params,
|
|
969
|
+
nextInput: params.candidate
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
function emitFinalRemainder(params) {
|
|
973
|
+
var _a;
|
|
974
|
+
const result = emitDelta({
|
|
975
|
+
...params,
|
|
976
|
+
nextInput: params.finalFullJson
|
|
977
|
+
});
|
|
978
|
+
if (!result && params.state.emittedInput.length > 0) {
|
|
979
|
+
(_a = params.onMismatch) == null ? void 0 : _a.call(
|
|
980
|
+
params,
|
|
981
|
+
"Final JSON does not extend emitted tool-input prefix",
|
|
982
|
+
{
|
|
983
|
+
emittedLength: params.state.emittedInput.length,
|
|
984
|
+
finalLength: params.finalFullJson.length
|
|
985
|
+
}
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
return result;
|
|
989
|
+
}
|
|
990
|
+
|
|
523
991
|
// src/core/utils/xml-root-repair.ts
|
|
524
992
|
var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
|
|
525
993
|
function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
|
|
@@ -549,6 +1017,9 @@ function getToolSchema(tools, toolName) {
|
|
|
549
1017
|
var _a;
|
|
550
1018
|
return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
|
|
551
1019
|
}
|
|
1020
|
+
function shouldEmitRawToolCallTextOnError2(options) {
|
|
1021
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
1022
|
+
}
|
|
552
1023
|
function processToolCall(params) {
|
|
553
1024
|
var _a, _b;
|
|
554
1025
|
const { toolCall, tools, options, text, processedElements, parseOptions } = params;
|
|
@@ -561,7 +1032,7 @@ function processToolCall(params) {
|
|
|
561
1032
|
const parsed = parse2(toolCall.content, toolSchema, parseConfig);
|
|
562
1033
|
processedElements.push({
|
|
563
1034
|
type: "tool-call",
|
|
564
|
-
toolCallId:
|
|
1035
|
+
toolCallId: generateToolCallId(),
|
|
565
1036
|
toolName: toolCall.toolName,
|
|
566
1037
|
input: JSON.stringify(parsed)
|
|
567
1038
|
});
|
|
@@ -578,6 +1049,299 @@ function processToolCall(params) {
|
|
|
578
1049
|
processedElements.push({ type: "text", text: originalCallText });
|
|
579
1050
|
}
|
|
580
1051
|
}
|
|
1052
|
+
function parseXmlTagName(rawTagBody) {
|
|
1053
|
+
let index = 0;
|
|
1054
|
+
while (index < rawTagBody.length && WHITESPACE_REGEX.test(rawTagBody[index])) {
|
|
1055
|
+
index += 1;
|
|
1056
|
+
}
|
|
1057
|
+
const nameStart = index;
|
|
1058
|
+
while (index < rawTagBody.length && NAME_CHAR_RE.test(rawTagBody.charAt(index))) {
|
|
1059
|
+
index += 1;
|
|
1060
|
+
}
|
|
1061
|
+
return rawTagBody.slice(nameStart, index);
|
|
1062
|
+
}
|
|
1063
|
+
function consumeXmlSpecialSection(fragment, ltIndex) {
|
|
1064
|
+
if (fragment.startsWith("<!--", ltIndex)) {
|
|
1065
|
+
const commentEnd = fragment.indexOf("-->", ltIndex + 4);
|
|
1066
|
+
return commentEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: commentEnd + 3 };
|
|
1067
|
+
}
|
|
1068
|
+
if (fragment.startsWith("<![CDATA[", ltIndex)) {
|
|
1069
|
+
const cdataEnd = fragment.indexOf("]]>", ltIndex + 9);
|
|
1070
|
+
return cdataEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: cdataEnd + 3 };
|
|
1071
|
+
}
|
|
1072
|
+
if (fragment.startsWith("<?", ltIndex)) {
|
|
1073
|
+
const processingEnd = fragment.indexOf("?>", ltIndex + 2);
|
|
1074
|
+
return processingEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: processingEnd + 2 };
|
|
1075
|
+
}
|
|
1076
|
+
if (fragment.startsWith("<!", ltIndex)) {
|
|
1077
|
+
const declarationEnd = fragment.indexOf(">", ltIndex + 2);
|
|
1078
|
+
return declarationEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: declarationEnd + 1 };
|
|
1079
|
+
}
|
|
1080
|
+
return { kind: "none" };
|
|
1081
|
+
}
|
|
1082
|
+
function parseXmlTagToken(fragment, ltIndex) {
|
|
1083
|
+
const gtIndex = fragment.indexOf(">", ltIndex + 1);
|
|
1084
|
+
if (gtIndex === -1) {
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
const tagBody = fragment.slice(ltIndex + 1, gtIndex).trim();
|
|
1088
|
+
if (tagBody.length === 0) {
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
if (tagBody.startsWith("/")) {
|
|
1092
|
+
const closeName = parseXmlTagName(tagBody.slice(1));
|
|
1093
|
+
if (closeName.length === 0) {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
return { kind: "close", name: closeName, nextPos: gtIndex + 1 };
|
|
1097
|
+
}
|
|
1098
|
+
const selfClosing = tagBody.endsWith("/");
|
|
1099
|
+
const openBody = selfClosing ? tagBody.slice(0, -1).trimEnd() : tagBody;
|
|
1100
|
+
const openName = parseXmlTagName(openBody);
|
|
1101
|
+
if (openName.length === 0) {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
kind: "open",
|
|
1106
|
+
name: openName,
|
|
1107
|
+
selfClosing,
|
|
1108
|
+
nextPos: gtIndex + 1
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function analyzeXmlFragmentForProgress(fragment) {
|
|
1112
|
+
const stack = [];
|
|
1113
|
+
const topLevelTagNames = [];
|
|
1114
|
+
let position = 0;
|
|
1115
|
+
while (position < fragment.length) {
|
|
1116
|
+
const ltIndex = fragment.indexOf("<", position);
|
|
1117
|
+
if (ltIndex === -1) {
|
|
1118
|
+
break;
|
|
1119
|
+
}
|
|
1120
|
+
const special = consumeXmlSpecialSection(fragment, ltIndex);
|
|
1121
|
+
if (special.kind === "incomplete") {
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
if (special.kind === "consumed") {
|
|
1125
|
+
position = special.nextPos;
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
const token = parseXmlTagToken(fragment, ltIndex);
|
|
1129
|
+
if (token === null) {
|
|
1130
|
+
return null;
|
|
1131
|
+
}
|
|
1132
|
+
if (token.kind === "close") {
|
|
1133
|
+
const openName = stack.pop();
|
|
1134
|
+
if (!openName || openName !== token.name) {
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
position = token.nextPos;
|
|
1138
|
+
continue;
|
|
1139
|
+
}
|
|
1140
|
+
if (stack.length === 0) {
|
|
1141
|
+
topLevelTagNames.push(token.name);
|
|
1142
|
+
}
|
|
1143
|
+
if (!token.selfClosing) {
|
|
1144
|
+
stack.push(token.name);
|
|
1145
|
+
}
|
|
1146
|
+
position = token.nextPos;
|
|
1147
|
+
}
|
|
1148
|
+
if (stack.length > 0) {
|
|
1149
|
+
return null;
|
|
1150
|
+
}
|
|
1151
|
+
return { topLevelTagNames };
|
|
1152
|
+
}
|
|
1153
|
+
function scanXmlFragmentTopLevelTextStep(options) {
|
|
1154
|
+
const { fragment, position, stack } = options;
|
|
1155
|
+
const ltIndex = fragment.indexOf("<", position);
|
|
1156
|
+
if (ltIndex === -1) {
|
|
1157
|
+
const trailingText = fragment.slice(position);
|
|
1158
|
+
return {
|
|
1159
|
+
kind: "done",
|
|
1160
|
+
value: stack.length === 0 && trailingText.trim().length > 0
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
const textBetweenTags = fragment.slice(position, ltIndex);
|
|
1164
|
+
if (stack.length === 0 && textBetweenTags.trim().length > 0) {
|
|
1165
|
+
return { kind: "found" };
|
|
1166
|
+
}
|
|
1167
|
+
const special = consumeXmlSpecialSection(fragment, ltIndex);
|
|
1168
|
+
if (special.kind === "incomplete") {
|
|
1169
|
+
return { kind: "invalid" };
|
|
1170
|
+
}
|
|
1171
|
+
if (special.kind === "consumed") {
|
|
1172
|
+
return { kind: "next", nextPos: special.nextPos };
|
|
1173
|
+
}
|
|
1174
|
+
const token = parseXmlTagToken(fragment, ltIndex);
|
|
1175
|
+
if (token === null) {
|
|
1176
|
+
return { kind: "invalid" };
|
|
1177
|
+
}
|
|
1178
|
+
if (token.kind === "close") {
|
|
1179
|
+
const openName = stack.pop();
|
|
1180
|
+
if (!openName || openName !== token.name) {
|
|
1181
|
+
return { kind: "invalid" };
|
|
1182
|
+
}
|
|
1183
|
+
} else if (!token.selfClosing) {
|
|
1184
|
+
stack.push(token.name);
|
|
1185
|
+
}
|
|
1186
|
+
return { kind: "next", nextPos: token.nextPos };
|
|
1187
|
+
}
|
|
1188
|
+
function hasNonWhitespaceTopLevelText(fragment) {
|
|
1189
|
+
if (!fragment.includes("<")) {
|
|
1190
|
+
return fragment.trim().length > 0;
|
|
1191
|
+
}
|
|
1192
|
+
const stack = [];
|
|
1193
|
+
let position = 0;
|
|
1194
|
+
while (position < fragment.length) {
|
|
1195
|
+
const step = scanXmlFragmentTopLevelTextStep({ fragment, position, stack });
|
|
1196
|
+
if (step.kind === "found") {
|
|
1197
|
+
return true;
|
|
1198
|
+
}
|
|
1199
|
+
if (step.kind === "invalid") {
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1202
|
+
if (step.kind === "done") {
|
|
1203
|
+
return step.value;
|
|
1204
|
+
}
|
|
1205
|
+
position = step.nextPos;
|
|
1206
|
+
}
|
|
1207
|
+
return false;
|
|
1208
|
+
}
|
|
1209
|
+
function getObjectSchemaPropertyNames(schema) {
|
|
1210
|
+
if (!schema || typeof schema !== "object") {
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
1213
|
+
const schemaObject = schema;
|
|
1214
|
+
const typeValue = schemaObject.type;
|
|
1215
|
+
if (typeValue != null) {
|
|
1216
|
+
const isObjectType = typeValue === "object" || Array.isArray(typeValue) && typeValue.includes("object");
|
|
1217
|
+
if (!isObjectType) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
if (!schemaObject.properties || typeof schemaObject.properties !== "object") {
|
|
1222
|
+
return /* @__PURE__ */ new Set();
|
|
1223
|
+
}
|
|
1224
|
+
return new Set(
|
|
1225
|
+
Object.keys(schemaObject.properties)
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
function schemaAllowsArrayType(schema) {
|
|
1229
|
+
if (!schema || typeof schema !== "object") {
|
|
1230
|
+
return false;
|
|
1231
|
+
}
|
|
1232
|
+
const schemaRecord = schema;
|
|
1233
|
+
const typeValue = schemaRecord.type;
|
|
1234
|
+
if (typeValue === "array") {
|
|
1235
|
+
return true;
|
|
1236
|
+
}
|
|
1237
|
+
if (Array.isArray(typeValue) && typeValue.includes("array")) {
|
|
1238
|
+
return true;
|
|
1239
|
+
}
|
|
1240
|
+
const unions = [schemaRecord.anyOf, schemaRecord.oneOf, schemaRecord.allOf];
|
|
1241
|
+
for (const union of unions) {
|
|
1242
|
+
if (!Array.isArray(union)) {
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
if (union.some((entry) => schemaAllowsArrayType(entry))) {
|
|
1246
|
+
return true;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
function getSchemaObjectProperty(schema, propertyName) {
|
|
1252
|
+
if (!schema || typeof schema !== "object") {
|
|
1253
|
+
return null;
|
|
1254
|
+
}
|
|
1255
|
+
const schemaObject = schema;
|
|
1256
|
+
const properties = schemaObject.properties;
|
|
1257
|
+
if (!properties || typeof properties !== "object") {
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
const property = properties[propertyName];
|
|
1261
|
+
if (!property) {
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
return property;
|
|
1265
|
+
}
|
|
1266
|
+
function isStableXmlProgressCandidate(options) {
|
|
1267
|
+
const { candidate, parsed, toolSchema } = options;
|
|
1268
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
const structure = analyzeXmlFragmentForProgress(candidate);
|
|
1272
|
+
if (!structure) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
const schemaProperties = getObjectSchemaPropertyNames(toolSchema);
|
|
1276
|
+
if (!schemaProperties || schemaProperties.size === 0) {
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
const parsedObject = parsed;
|
|
1280
|
+
const uniqueTopLevelTags = new Set(structure.topLevelTagNames);
|
|
1281
|
+
for (const tagName of uniqueTopLevelTags) {
|
|
1282
|
+
if (!schemaProperties.has(tagName)) {
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
const schemaProperty = getSchemaObjectProperty(toolSchema, tagName);
|
|
1286
|
+
if (schemaProperty && schemaAllowsArrayType(schemaProperty) && !Array.isArray(parsedObject[tagName])) {
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
if (structure.topLevelTagNames.length === 1) {
|
|
1291
|
+
const onlyTopLevelTag = structure.topLevelTagNames[0];
|
|
1292
|
+
if (!schemaProperties || schemaProperties.size === 0 || !schemaProperties.has(onlyTopLevelTag)) {
|
|
1293
|
+
return false;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
return true;
|
|
1297
|
+
}
|
|
1298
|
+
function parseXmlContentForStreamProgress({
|
|
1299
|
+
toolContent,
|
|
1300
|
+
toolSchema,
|
|
1301
|
+
parseOptions
|
|
1302
|
+
}) {
|
|
1303
|
+
const tryParse = (content) => {
|
|
1304
|
+
try {
|
|
1305
|
+
return parse2(content, toolSchema, {
|
|
1306
|
+
...parseOptions != null ? parseOptions : {},
|
|
1307
|
+
repair: false,
|
|
1308
|
+
onError: void 0
|
|
1309
|
+
});
|
|
1310
|
+
} catch (e) {
|
|
1311
|
+
return null;
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
const strictFull = tryParse(toolContent);
|
|
1315
|
+
if (strictFull !== null && isStableXmlProgressCandidate({
|
|
1316
|
+
candidate: toolContent,
|
|
1317
|
+
parsed: strictFull,
|
|
1318
|
+
toolSchema
|
|
1319
|
+
})) {
|
|
1320
|
+
return JSON.stringify(strictFull);
|
|
1321
|
+
}
|
|
1322
|
+
let searchEnd = toolContent.length;
|
|
1323
|
+
while (searchEnd > 0) {
|
|
1324
|
+
const gtIndex = toolContent.lastIndexOf(">", searchEnd - 1);
|
|
1325
|
+
if (gtIndex === -1) {
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
const candidate = toolContent.slice(0, gtIndex + 1);
|
|
1329
|
+
if (!analyzeXmlFragmentForProgress(candidate)) {
|
|
1330
|
+
searchEnd = gtIndex;
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
const parsedCandidate = tryParse(candidate);
|
|
1334
|
+
if (parsedCandidate !== null && isStableXmlProgressCandidate({
|
|
1335
|
+
candidate,
|
|
1336
|
+
parsed: parsedCandidate,
|
|
1337
|
+
toolSchema
|
|
1338
|
+
})) {
|
|
1339
|
+
return JSON.stringify(parsedCandidate);
|
|
1340
|
+
}
|
|
1341
|
+
searchEnd = gtIndex;
|
|
1342
|
+
}
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
581
1345
|
function handleStreamingToolCallEnd(params) {
|
|
582
1346
|
var _a, _b;
|
|
583
1347
|
const {
|
|
@@ -597,19 +1361,37 @@ function handleStreamingToolCallEnd(params) {
|
|
|
597
1361
|
flushText(ctrl);
|
|
598
1362
|
try {
|
|
599
1363
|
const parsedResult = parse2(toolContent, toolSchema, parseConfig);
|
|
1364
|
+
const finalInput = JSON.stringify(parsedResult);
|
|
1365
|
+
emitFinalRemainder({
|
|
1366
|
+
controller: ctrl,
|
|
1367
|
+
id: currentToolCall.toolCallId,
|
|
1368
|
+
state: currentToolCall,
|
|
1369
|
+
finalFullJson: finalInput,
|
|
1370
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
1371
|
+
});
|
|
1372
|
+
ctrl.enqueue({
|
|
1373
|
+
type: "tool-input-end",
|
|
1374
|
+
id: currentToolCall.toolCallId
|
|
1375
|
+
});
|
|
600
1376
|
ctrl.enqueue({
|
|
601
1377
|
type: "tool-call",
|
|
602
|
-
toolCallId:
|
|
1378
|
+
toolCallId: currentToolCall.toolCallId,
|
|
603
1379
|
toolName: currentToolCall.name,
|
|
604
|
-
input:
|
|
1380
|
+
input: finalInput
|
|
605
1381
|
});
|
|
606
1382
|
} catch (error) {
|
|
1383
|
+
ctrl.enqueue({
|
|
1384
|
+
type: "tool-input-end",
|
|
1385
|
+
id: currentToolCall.toolCallId
|
|
1386
|
+
});
|
|
607
1387
|
const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
|
|
608
1388
|
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
|
|
609
1389
|
toolCall: original,
|
|
610
1390
|
error
|
|
611
1391
|
});
|
|
612
|
-
|
|
1392
|
+
if (shouldEmitRawToolCallTextOnError2(options)) {
|
|
1393
|
+
flushText(ctrl, original);
|
|
1394
|
+
}
|
|
613
1395
|
}
|
|
614
1396
|
}
|
|
615
1397
|
function findClosingTagEndFlexible(text, contentStart, toolName) {
|
|
@@ -1031,38 +1813,6 @@ function findPotentialToolTagStart(buffer, toolNames) {
|
|
|
1031
1813
|
}
|
|
1032
1814
|
return -1;
|
|
1033
1815
|
}
|
|
1034
|
-
function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
1035
|
-
return (controller, text) => {
|
|
1036
|
-
const content = text;
|
|
1037
|
-
if (content) {
|
|
1038
|
-
if (!getCurrentTextId()) {
|
|
1039
|
-
const newId = generateId();
|
|
1040
|
-
setCurrentTextId(newId);
|
|
1041
|
-
controller.enqueue({
|
|
1042
|
-
type: "text-start",
|
|
1043
|
-
id: newId
|
|
1044
|
-
});
|
|
1045
|
-
setHasEmittedTextStart(true);
|
|
1046
|
-
}
|
|
1047
|
-
controller.enqueue({
|
|
1048
|
-
type: "text-delta",
|
|
1049
|
-
id: getCurrentTextId(),
|
|
1050
|
-
delta: content
|
|
1051
|
-
});
|
|
1052
|
-
}
|
|
1053
|
-
const currentTextId = getCurrentTextId();
|
|
1054
|
-
if (currentTextId && !text) {
|
|
1055
|
-
if (getHasEmittedTextStart()) {
|
|
1056
|
-
controller.enqueue({
|
|
1057
|
-
type: "text-end",
|
|
1058
|
-
id: currentTextId
|
|
1059
|
-
});
|
|
1060
|
-
setHasEmittedTextStart(false);
|
|
1061
|
-
}
|
|
1062
|
-
setCurrentTextId(null);
|
|
1063
|
-
}
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
1816
|
function processToolCallInBuffer(params) {
|
|
1067
1817
|
const {
|
|
1068
1818
|
buffer,
|
|
@@ -1072,18 +1822,21 @@ function processToolCallInBuffer(params) {
|
|
|
1072
1822
|
controller,
|
|
1073
1823
|
flushText,
|
|
1074
1824
|
setBuffer,
|
|
1075
|
-
parseOptions
|
|
1825
|
+
parseOptions,
|
|
1826
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
1076
1827
|
} = params;
|
|
1077
1828
|
const endTagPattern = new RegExp(
|
|
1078
1829
|
`</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
|
|
1079
1830
|
);
|
|
1080
1831
|
const endMatch = endTagPattern.exec(buffer);
|
|
1081
1832
|
if (!endMatch || endMatch.index === void 0) {
|
|
1833
|
+
emitToolInputProgress2(controller, currentToolCall, buffer);
|
|
1082
1834
|
return { buffer, currentToolCall, shouldBreak: true };
|
|
1083
1835
|
}
|
|
1084
1836
|
const endIdx = endMatch.index;
|
|
1085
1837
|
const endPos = endIdx + endMatch[0].length;
|
|
1086
1838
|
const content = buffer.substring(0, endIdx);
|
|
1839
|
+
emitToolInputProgress2(controller, currentToolCall, content);
|
|
1087
1840
|
const remainder = buffer.substring(endPos);
|
|
1088
1841
|
setBuffer(remainder);
|
|
1089
1842
|
handleStreamingToolCallEnd({
|
|
@@ -1110,7 +1863,8 @@ function processNoToolCallInBuffer(params) {
|
|
|
1110
1863
|
tools,
|
|
1111
1864
|
options,
|
|
1112
1865
|
parseOptions,
|
|
1113
|
-
setBuffer
|
|
1866
|
+
setBuffer,
|
|
1867
|
+
emitToolInputStart
|
|
1114
1868
|
} = params;
|
|
1115
1869
|
const {
|
|
1116
1870
|
index: earliestStartTagIndex,
|
|
@@ -1140,9 +1894,10 @@ function processNoToolCallInBuffer(params) {
|
|
|
1140
1894
|
if (selfClosing) {
|
|
1141
1895
|
const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
|
|
1142
1896
|
setBuffer(newBuffer2);
|
|
1897
|
+
const currentToolCall = emitToolInputStart(controller, earliestToolName);
|
|
1143
1898
|
handleStreamingToolCallEnd({
|
|
1144
1899
|
toolContent: "",
|
|
1145
|
-
currentToolCall
|
|
1900
|
+
currentToolCall,
|
|
1146
1901
|
tools,
|
|
1147
1902
|
options,
|
|
1148
1903
|
ctrl: controller,
|
|
@@ -1161,12 +1916,12 @@ function processNoToolCallInBuffer(params) {
|
|
|
1161
1916
|
setBuffer(newBuffer);
|
|
1162
1917
|
return {
|
|
1163
1918
|
buffer: newBuffer,
|
|
1164
|
-
currentToolCall:
|
|
1919
|
+
currentToolCall: emitToolInputStart(controller, earliestToolName),
|
|
1165
1920
|
shouldBreak: false,
|
|
1166
1921
|
shouldContinue: true
|
|
1167
1922
|
};
|
|
1168
1923
|
}
|
|
1169
|
-
function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions) {
|
|
1924
|
+
function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions, emitToolInputProgress2, emitToolInputStart) {
|
|
1170
1925
|
return (controller) => {
|
|
1171
1926
|
while (true) {
|
|
1172
1927
|
const currentToolCall = getCurrentToolCall();
|
|
@@ -1179,7 +1934,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1179
1934
|
controller,
|
|
1180
1935
|
flushText,
|
|
1181
1936
|
setBuffer,
|
|
1182
|
-
parseOptions
|
|
1937
|
+
parseOptions,
|
|
1938
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
1183
1939
|
});
|
|
1184
1940
|
setBuffer(result.buffer);
|
|
1185
1941
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1195,7 +1951,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1195
1951
|
tools,
|
|
1196
1952
|
options,
|
|
1197
1953
|
parseOptions,
|
|
1198
|
-
setBuffer
|
|
1954
|
+
setBuffer,
|
|
1955
|
+
emitToolInputStart
|
|
1199
1956
|
});
|
|
1200
1957
|
setBuffer(result.buffer);
|
|
1201
1958
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1308,7 +2065,119 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1308
2065
|
(value) => {
|
|
1309
2066
|
hasEmittedTextStart = value;
|
|
1310
2067
|
}
|
|
1311
|
-
);
|
|
2068
|
+
);
|
|
2069
|
+
const emitToolInputStart = (controller, toolName) => {
|
|
2070
|
+
flushText(controller);
|
|
2071
|
+
const next = {
|
|
2072
|
+
name: toolName,
|
|
2073
|
+
toolCallId: generateToolCallId(),
|
|
2074
|
+
emittedInput: "",
|
|
2075
|
+
lastProgressGtIndex: null,
|
|
2076
|
+
lastProgressFullInput: null
|
|
2077
|
+
};
|
|
2078
|
+
controller.enqueue({
|
|
2079
|
+
type: "tool-input-start",
|
|
2080
|
+
id: next.toolCallId,
|
|
2081
|
+
toolName
|
|
2082
|
+
});
|
|
2083
|
+
return next;
|
|
2084
|
+
};
|
|
2085
|
+
const emitToolInputProgress2 = (controller, toolCall, toolContent) => {
|
|
2086
|
+
const progressGtIndex = toolContent.lastIndexOf(">");
|
|
2087
|
+
if (toolCall.lastProgressGtIndex === progressGtIndex) {
|
|
2088
|
+
const cached = toolCall.lastProgressFullInput;
|
|
2089
|
+
if (cached == null) {
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
if (cached === "{}" && toolContent.trim().length === 0) {
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
const prefixCandidate2 = toIncompleteJsonPrefix(cached);
|
|
2096
|
+
emitPrefixDelta({
|
|
2097
|
+
controller,
|
|
2098
|
+
id: toolCall.toolCallId,
|
|
2099
|
+
state: toolCall,
|
|
2100
|
+
candidate: prefixCandidate2
|
|
2101
|
+
});
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
const toolSchema = getToolSchema(tools, toolCall.name);
|
|
2105
|
+
const fullInput = parseXmlContentForStreamProgress({
|
|
2106
|
+
toolContent,
|
|
2107
|
+
toolSchema,
|
|
2108
|
+
parseOptions
|
|
2109
|
+
});
|
|
2110
|
+
toolCall.lastProgressGtIndex = progressGtIndex;
|
|
2111
|
+
toolCall.lastProgressFullInput = fullInput;
|
|
2112
|
+
if (fullInput == null) {
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
if (fullInput === "{}" && toolContent.trim().length === 0) {
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
const prefixCandidate = toIncompleteJsonPrefix(fullInput);
|
|
2119
|
+
emitPrefixDelta({
|
|
2120
|
+
controller,
|
|
2121
|
+
id: toolCall.toolCallId,
|
|
2122
|
+
state: toolCall,
|
|
2123
|
+
candidate: prefixCandidate
|
|
2124
|
+
});
|
|
2125
|
+
};
|
|
2126
|
+
const finalizeUnclosedToolCall = (controller) => {
|
|
2127
|
+
var _a2, _b;
|
|
2128
|
+
if (!currentToolCall) {
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
emitToolInputProgress2(controller, currentToolCall, buffer);
|
|
2132
|
+
const parseConfig = {
|
|
2133
|
+
...parseOptions,
|
|
2134
|
+
onError: (_a2 = options == null ? void 0 : options.onError) != null ? _a2 : parseOptions == null ? void 0 : parseOptions.onError
|
|
2135
|
+
};
|
|
2136
|
+
const toolSchema = getToolSchema(tools, currentToolCall.name);
|
|
2137
|
+
flushText(controller);
|
|
2138
|
+
try {
|
|
2139
|
+
if (hasNonWhitespaceTopLevelText(buffer)) {
|
|
2140
|
+
throw new Error(
|
|
2141
|
+
"Cannot reconcile unclosed XML tool call with top-level plain text."
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
const parsedResult = parse2(buffer, toolSchema, parseConfig);
|
|
2145
|
+
const finalInput = JSON.stringify(parsedResult);
|
|
2146
|
+
emitFinalRemainder({
|
|
2147
|
+
controller,
|
|
2148
|
+
id: currentToolCall.toolCallId,
|
|
2149
|
+
state: currentToolCall,
|
|
2150
|
+
finalFullJson: finalInput,
|
|
2151
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2152
|
+
});
|
|
2153
|
+
controller.enqueue({
|
|
2154
|
+
type: "tool-input-end",
|
|
2155
|
+
id: currentToolCall.toolCallId
|
|
2156
|
+
});
|
|
2157
|
+
controller.enqueue({
|
|
2158
|
+
type: "tool-call",
|
|
2159
|
+
toolCallId: currentToolCall.toolCallId,
|
|
2160
|
+
toolName: currentToolCall.name,
|
|
2161
|
+
input: finalInput
|
|
2162
|
+
});
|
|
2163
|
+
} catch (error) {
|
|
2164
|
+
controller.enqueue({
|
|
2165
|
+
type: "tool-input-end",
|
|
2166
|
+
id: currentToolCall.toolCallId
|
|
2167
|
+
});
|
|
2168
|
+
const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
|
|
2169
|
+
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
|
|
2170
|
+
options,
|
|
2171
|
+
"Could not complete streaming XML tool call at finish.",
|
|
2172
|
+
{ toolCall: unfinishedContent, error }
|
|
2173
|
+
);
|
|
2174
|
+
if (shouldEmitRawToolCallTextOnError2(options)) {
|
|
2175
|
+
flushText(controller, unfinishedContent);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
buffer = "";
|
|
2179
|
+
currentToolCall = null;
|
|
2180
|
+
};
|
|
1312
2181
|
const processBuffer = createProcessBufferHandler(
|
|
1313
2182
|
() => buffer,
|
|
1314
2183
|
(newBuffer) => {
|
|
@@ -1322,17 +2191,17 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1322
2191
|
options,
|
|
1323
2192
|
toolNames,
|
|
1324
2193
|
flushText,
|
|
1325
|
-
parseOptions
|
|
2194
|
+
parseOptions,
|
|
2195
|
+
emitToolInputProgress2,
|
|
2196
|
+
emitToolInputStart
|
|
1326
2197
|
);
|
|
1327
2198
|
return new TransformStream({
|
|
2199
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Stateful stream parsing requires branching over chunk lifecycle and parser states.
|
|
1328
2200
|
transform(chunk, controller) {
|
|
1329
2201
|
var _a2;
|
|
1330
2202
|
if (chunk.type === "finish") {
|
|
1331
2203
|
if (currentToolCall) {
|
|
1332
|
-
|
|
1333
|
-
flushText(controller, unfinishedContent);
|
|
1334
|
-
buffer = "";
|
|
1335
|
-
currentToolCall = null;
|
|
2204
|
+
finalizeUnclosedToolCall(controller);
|
|
1336
2205
|
} else if (buffer) {
|
|
1337
2206
|
flushText(controller, buffer);
|
|
1338
2207
|
buffer = "";
|
|
@@ -1342,7 +2211,8 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1342
2211
|
return;
|
|
1343
2212
|
}
|
|
1344
2213
|
if (chunk.type !== "text-delta") {
|
|
1345
|
-
if (
|
|
2214
|
+
if (currentToolCall) {
|
|
2215
|
+
} else if (buffer) {
|
|
1346
2216
|
flushText(controller, buffer);
|
|
1347
2217
|
buffer = "";
|
|
1348
2218
|
}
|
|
@@ -1355,10 +2225,7 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1355
2225
|
},
|
|
1356
2226
|
flush(controller) {
|
|
1357
2227
|
if (currentToolCall) {
|
|
1358
|
-
|
|
1359
|
-
flushText(controller, unfinishedContent);
|
|
1360
|
-
buffer = "";
|
|
1361
|
-
currentToolCall = null;
|
|
2228
|
+
finalizeUnclosedToolCall(controller);
|
|
1362
2229
|
} else if (buffer) {
|
|
1363
2230
|
flushText(controller, buffer);
|
|
1364
2231
|
buffer = "";
|
|
@@ -1386,7 +2253,205 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1386
2253
|
|
|
1387
2254
|
// src/core/protocols/yaml-protocol.ts
|
|
1388
2255
|
import YAML from "yaml";
|
|
2256
|
+
function shouldEmitRawToolCallTextOnError3(options) {
|
|
2257
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
2258
|
+
}
|
|
2259
|
+
var selfClosingTagCache2 = /* @__PURE__ */ new Map();
|
|
2260
|
+
function getSelfClosingTagPattern2(toolName) {
|
|
2261
|
+
let pattern = selfClosingTagCache2.get(toolName);
|
|
2262
|
+
if (!pattern) {
|
|
2263
|
+
pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
|
|
2264
|
+
selfClosingTagCache2.set(toolName, pattern);
|
|
2265
|
+
}
|
|
2266
|
+
return pattern;
|
|
2267
|
+
}
|
|
1389
2268
|
var LEADING_WHITESPACE_RE = /^(\s*)/;
|
|
2269
|
+
var INCOMPLETE_MAPPING_TAIL_RE = /^[^:[\]{}-][^:]*:\s*$/;
|
|
2270
|
+
var INCOMPLETE_SEQUENCE_TAIL_RE = /^-\s*$/;
|
|
2271
|
+
var BLOCK_SCALAR_KEY_RE = /:\s*[|>][-+0-9]*\s*$/;
|
|
2272
|
+
var PLAIN_MAPPING_VALUE_RE = /^[^:[\]{}-][^:]*:\s*(.+)$/;
|
|
2273
|
+
var PLAIN_SEQUENCE_VALUE_RE = /^-\s+(.+)$/;
|
|
2274
|
+
function normalizeYamlContent(yamlContent) {
|
|
2275
|
+
let normalized = yamlContent;
|
|
2276
|
+
if (normalized.startsWith("\n")) {
|
|
2277
|
+
normalized = normalized.slice(1);
|
|
2278
|
+
}
|
|
2279
|
+
const lines = normalized.split("\n");
|
|
2280
|
+
const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
|
|
2281
|
+
if (nonEmptyLines.length === 0) {
|
|
2282
|
+
return { normalized: "", nonEmptyLines };
|
|
2283
|
+
}
|
|
2284
|
+
const minIndent = Math.min(
|
|
2285
|
+
...nonEmptyLines.map((line) => {
|
|
2286
|
+
const match = line.match(LEADING_WHITESPACE_RE);
|
|
2287
|
+
return match ? match[1].length : 0;
|
|
2288
|
+
})
|
|
2289
|
+
);
|
|
2290
|
+
if (minIndent > 0) {
|
|
2291
|
+
normalized = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
2292
|
+
}
|
|
2293
|
+
return { normalized, nonEmptyLines };
|
|
2294
|
+
}
|
|
2295
|
+
function parseYamlDocumentAsMapping(normalized) {
|
|
2296
|
+
try {
|
|
2297
|
+
const doc = YAML.parseDocument(normalized);
|
|
2298
|
+
const errors = doc.errors.map((e) => e.message);
|
|
2299
|
+
const result = doc.toJSON();
|
|
2300
|
+
if (result === null) {
|
|
2301
|
+
return { value: {}, errors };
|
|
2302
|
+
}
|
|
2303
|
+
if (typeof result !== "object" || Array.isArray(result)) {
|
|
2304
|
+
return { value: null, errors };
|
|
2305
|
+
}
|
|
2306
|
+
return { value: result, errors };
|
|
2307
|
+
} catch (error) {
|
|
2308
|
+
return {
|
|
2309
|
+
value: null,
|
|
2310
|
+
errors: [
|
|
2311
|
+
error instanceof Error ? error.message : "Unknown YAML parsing error"
|
|
2312
|
+
]
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
function getLastMeaningfulLineInfo(input) {
|
|
2317
|
+
var _a;
|
|
2318
|
+
const lines = input.split("\n");
|
|
2319
|
+
let index = lines.length - 1;
|
|
2320
|
+
while (index >= 0) {
|
|
2321
|
+
const raw = (_a = lines[index]) != null ? _a : "";
|
|
2322
|
+
const trimmed = raw.trim();
|
|
2323
|
+
if (trimmed.length > 0 && !trimmed.startsWith("#")) {
|
|
2324
|
+
return {
|
|
2325
|
+
index,
|
|
2326
|
+
raw,
|
|
2327
|
+
trimmed,
|
|
2328
|
+
indent: raw.length - raw.trimStart().length
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
index -= 1;
|
|
2332
|
+
}
|
|
2333
|
+
return null;
|
|
2334
|
+
}
|
|
2335
|
+
function dropLastMeaningfulLine(input) {
|
|
2336
|
+
const lineInfo = getLastMeaningfulLineInfo(input);
|
|
2337
|
+
if (!lineInfo) {
|
|
2338
|
+
return null;
|
|
2339
|
+
}
|
|
2340
|
+
return input.split("\n").slice(0, lineInfo.index).join("\n").trimEnd();
|
|
2341
|
+
}
|
|
2342
|
+
function hasIncompleteMappingTail(normalized) {
|
|
2343
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2344
|
+
if (!lineInfo) {
|
|
2345
|
+
return false;
|
|
2346
|
+
}
|
|
2347
|
+
return INCOMPLETE_MAPPING_TAIL_RE.test(lineInfo.trimmed);
|
|
2348
|
+
}
|
|
2349
|
+
function hasIncompleteSequenceTail(normalized) {
|
|
2350
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2351
|
+
if (!lineInfo) {
|
|
2352
|
+
return false;
|
|
2353
|
+
}
|
|
2354
|
+
return INCOMPLETE_SEQUENCE_TAIL_RE.test(lineInfo.trimmed);
|
|
2355
|
+
}
|
|
2356
|
+
function hasSplitNestedKeyTail(normalized) {
|
|
2357
|
+
var _a;
|
|
2358
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2359
|
+
if (!lineInfo) {
|
|
2360
|
+
return false;
|
|
2361
|
+
}
|
|
2362
|
+
const { trimmed, indent, index } = lineInfo;
|
|
2363
|
+
if (indent === 0) {
|
|
2364
|
+
return false;
|
|
2365
|
+
}
|
|
2366
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("-") || trimmed.includes(":")) {
|
|
2367
|
+
return false;
|
|
2368
|
+
}
|
|
2369
|
+
const lines = normalized.split("\n");
|
|
2370
|
+
let parentIndex = index - 1;
|
|
2371
|
+
while (parentIndex >= 0) {
|
|
2372
|
+
const parentRaw = (_a = lines[parentIndex]) != null ? _a : "";
|
|
2373
|
+
const parentTrimmed = parentRaw.trim();
|
|
2374
|
+
if (parentTrimmed.length === 0 || parentTrimmed.startsWith("#")) {
|
|
2375
|
+
parentIndex -= 1;
|
|
2376
|
+
continue;
|
|
2377
|
+
}
|
|
2378
|
+
const parentIndent = parentRaw.length - parentRaw.trimStart().length;
|
|
2379
|
+
if (parentIndent >= indent) {
|
|
2380
|
+
parentIndex -= 1;
|
|
2381
|
+
continue;
|
|
2382
|
+
}
|
|
2383
|
+
if (!parentTrimmed.endsWith(":")) {
|
|
2384
|
+
return false;
|
|
2385
|
+
}
|
|
2386
|
+
if (BLOCK_SCALAR_KEY_RE.test(parentTrimmed)) {
|
|
2387
|
+
return false;
|
|
2388
|
+
}
|
|
2389
|
+
return true;
|
|
2390
|
+
}
|
|
2391
|
+
return false;
|
|
2392
|
+
}
|
|
2393
|
+
function extractTrailingPlainScalarValue(line) {
|
|
2394
|
+
var _a;
|
|
2395
|
+
if (BLOCK_SCALAR_KEY_RE.test(line)) {
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
const mappingMatch = line.match(PLAIN_MAPPING_VALUE_RE);
|
|
2399
|
+
const sequenceMatch = line.match(PLAIN_SEQUENCE_VALUE_RE);
|
|
2400
|
+
const value = (_a = mappingMatch == null ? void 0 : mappingMatch[1]) != null ? _a : sequenceMatch == null ? void 0 : sequenceMatch[1];
|
|
2401
|
+
if (!value) {
|
|
2402
|
+
return null;
|
|
2403
|
+
}
|
|
2404
|
+
const trimmedValue = value.trim();
|
|
2405
|
+
if (trimmedValue.length === 0) {
|
|
2406
|
+
return null;
|
|
2407
|
+
}
|
|
2408
|
+
if (trimmedValue.startsWith('"') || trimmedValue.startsWith("'")) {
|
|
2409
|
+
return null;
|
|
2410
|
+
}
|
|
2411
|
+
if (trimmedValue.startsWith("{") || trimmedValue.startsWith("[") || trimmedValue.startsWith("|") || trimmedValue.startsWith(">")) {
|
|
2412
|
+
return null;
|
|
2413
|
+
}
|
|
2414
|
+
return trimmedValue;
|
|
2415
|
+
}
|
|
2416
|
+
function hasUnterminatedPlainScalarTail(normalized) {
|
|
2417
|
+
if (normalized.endsWith("\n")) {
|
|
2418
|
+
return false;
|
|
2419
|
+
}
|
|
2420
|
+
const lineInfo = getLastMeaningfulLineInfo(normalized);
|
|
2421
|
+
if (!lineInfo) {
|
|
2422
|
+
return false;
|
|
2423
|
+
}
|
|
2424
|
+
return extractTrailingPlainScalarValue(lineInfo.trimmed) != null;
|
|
2425
|
+
}
|
|
2426
|
+
function hasUnstableProgressTail(normalized) {
|
|
2427
|
+
return hasIncompleteMappingTail(normalized) || hasIncompleteSequenceTail(normalized) || hasSplitNestedKeyTail(normalized) || hasUnterminatedPlainScalarTail(normalized);
|
|
2428
|
+
}
|
|
2429
|
+
function trimTrailingNewlineInUnknown(value) {
|
|
2430
|
+
if (typeof value === "string") {
|
|
2431
|
+
if (value.endsWith("\n")) {
|
|
2432
|
+
return value.slice(0, -1);
|
|
2433
|
+
}
|
|
2434
|
+
return value;
|
|
2435
|
+
}
|
|
2436
|
+
if (Array.isArray(value)) {
|
|
2437
|
+
return value.map((item) => trimTrailingNewlineInUnknown(item));
|
|
2438
|
+
}
|
|
2439
|
+
if (value && typeof value === "object") {
|
|
2440
|
+
return Object.fromEntries(
|
|
2441
|
+
Object.entries(value).map(([key, item]) => [
|
|
2442
|
+
key,
|
|
2443
|
+
trimTrailingNewlineInUnknown(item)
|
|
2444
|
+
])
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
return value;
|
|
2448
|
+
}
|
|
2449
|
+
function stabilizeParsedValueForStreamProgress(value, source) {
|
|
2450
|
+
if (source.endsWith("\n")) {
|
|
2451
|
+
return value;
|
|
2452
|
+
}
|
|
2453
|
+
return trimTrailingNewlineInUnknown(value);
|
|
2454
|
+
}
|
|
1390
2455
|
function findClosingTagEnd(text, contentStart, toolName) {
|
|
1391
2456
|
let pos = contentStart;
|
|
1392
2457
|
let depth = 1;
|
|
@@ -1458,9 +2523,9 @@ function findEarliestTagPosition(openIdx, selfIdx) {
|
|
|
1458
2523
|
function collectToolCallsForName(text, toolName) {
|
|
1459
2524
|
const toolCalls = [];
|
|
1460
2525
|
let searchIndex = 0;
|
|
1461
|
-
const
|
|
2526
|
+
const startTag = `<${toolName}>`;
|
|
2527
|
+
const selfTagRegex = getSelfClosingTagPattern2(toolName);
|
|
1462
2528
|
while (searchIndex < text.length) {
|
|
1463
|
-
const startTag = `<${toolName}>`;
|
|
1464
2529
|
const openIdx = text.indexOf(startTag, searchIndex);
|
|
1465
2530
|
selfTagRegex.lastIndex = searchIndex;
|
|
1466
2531
|
const selfMatch = selfTagRegex.exec(text);
|
|
@@ -1510,47 +2575,48 @@ function findToolCalls2(text, toolNames) {
|
|
|
1510
2575
|
return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
|
|
1511
2576
|
}
|
|
1512
2577
|
function parseYamlContent(yamlContent, options) {
|
|
1513
|
-
var _a, _b
|
|
1514
|
-
|
|
1515
|
-
if (normalized.startsWith("\n")) {
|
|
1516
|
-
normalized = normalized.slice(1);
|
|
1517
|
-
}
|
|
1518
|
-
const lines = normalized.split("\n");
|
|
1519
|
-
const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
|
|
2578
|
+
var _a, _b;
|
|
2579
|
+
const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
|
|
1520
2580
|
if (nonEmptyLines.length === 0) {
|
|
1521
2581
|
return {};
|
|
1522
2582
|
}
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
})
|
|
1528
|
-
|
|
1529
|
-
if (minIndent > 0) {
|
|
1530
|
-
normalized = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
2583
|
+
const parsed = parseYamlDocumentAsMapping(normalized);
|
|
2584
|
+
if (parsed.errors.length > 0) {
|
|
2585
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
|
|
2586
|
+
errors: parsed.errors
|
|
2587
|
+
});
|
|
2588
|
+
return null;
|
|
1531
2589
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
2590
|
+
if (parsed.value === null) {
|
|
2591
|
+
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
|
|
2592
|
+
got: "non-mapping"
|
|
2593
|
+
});
|
|
2594
|
+
return null;
|
|
2595
|
+
}
|
|
2596
|
+
return parsed.value;
|
|
2597
|
+
}
|
|
2598
|
+
function parseYamlContentForStreamProgress(yamlContent) {
|
|
2599
|
+
const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
|
|
2600
|
+
if (nonEmptyLines.length === 0) {
|
|
2601
|
+
return {};
|
|
2602
|
+
}
|
|
2603
|
+
let candidate = normalized;
|
|
2604
|
+
while (true) {
|
|
2605
|
+
const parsed = parseYamlDocumentAsMapping(candidate);
|
|
2606
|
+
if (parsed.errors.length === 0 && !hasUnstableProgressTail(candidate)) {
|
|
2607
|
+
if (candidate.trim().length === 0 && normalized.trim().length > 0) {
|
|
2608
|
+
return null;
|
|
2609
|
+
}
|
|
2610
|
+
return stabilizeParsedValueForStreamProgress(parsed.value, candidate);
|
|
1539
2611
|
}
|
|
1540
|
-
const
|
|
1541
|
-
if (
|
|
1542
|
-
return
|
|
2612
|
+
const truncated = dropLastMeaningfulLine(candidate);
|
|
2613
|
+
if (truncated == null) {
|
|
2614
|
+
return null;
|
|
1543
2615
|
}
|
|
1544
|
-
if (
|
|
1545
|
-
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
|
|
1546
|
-
got: typeof result
|
|
1547
|
-
});
|
|
2616
|
+
if (truncated === candidate) {
|
|
1548
2617
|
return null;
|
|
1549
2618
|
}
|
|
1550
|
-
|
|
1551
|
-
} catch (error) {
|
|
1552
|
-
(_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, "Failed to parse YAML content", { error });
|
|
1553
|
-
return null;
|
|
2619
|
+
candidate = truncated;
|
|
1554
2620
|
}
|
|
1555
2621
|
}
|
|
1556
2622
|
function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
|
|
@@ -1566,7 +2632,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1566
2632
|
if (parsedArgs !== null) {
|
|
1567
2633
|
processedElements.push({
|
|
1568
2634
|
type: "tool-call",
|
|
1569
|
-
toolCallId:
|
|
2635
|
+
toolCallId: generateToolCallId(),
|
|
1570
2636
|
toolName: tc.toolName,
|
|
1571
2637
|
input: JSON.stringify(parsedArgs)
|
|
1572
2638
|
});
|
|
@@ -1579,38 +2645,6 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1579
2645
|
}
|
|
1580
2646
|
return tc.endIndex;
|
|
1581
2647
|
}
|
|
1582
|
-
function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
|
|
1583
|
-
return (controller, text) => {
|
|
1584
|
-
const content = text;
|
|
1585
|
-
if (content) {
|
|
1586
|
-
if (!getCurrentTextId()) {
|
|
1587
|
-
const newId = generateId();
|
|
1588
|
-
setCurrentTextId(newId);
|
|
1589
|
-
controller.enqueue({
|
|
1590
|
-
type: "text-start",
|
|
1591
|
-
id: newId
|
|
1592
|
-
});
|
|
1593
|
-
setHasEmittedTextStart(true);
|
|
1594
|
-
}
|
|
1595
|
-
controller.enqueue({
|
|
1596
|
-
type: "text-delta",
|
|
1597
|
-
id: getCurrentTextId(),
|
|
1598
|
-
delta: content
|
|
1599
|
-
});
|
|
1600
|
-
}
|
|
1601
|
-
const currentTextId = getCurrentTextId();
|
|
1602
|
-
if (currentTextId && !text) {
|
|
1603
|
-
if (getHasEmittedTextStart()) {
|
|
1604
|
-
controller.enqueue({
|
|
1605
|
-
type: "text-end",
|
|
1606
|
-
id: currentTextId
|
|
1607
|
-
});
|
|
1608
|
-
setHasEmittedTextStart(false);
|
|
1609
|
-
}
|
|
1610
|
-
setCurrentTextId(null);
|
|
1611
|
-
}
|
|
1612
|
-
};
|
|
1613
|
-
}
|
|
1614
2648
|
function findEarliestToolTag2(buffer, toolNames) {
|
|
1615
2649
|
let bestIndex = -1;
|
|
1616
2650
|
let bestName = "";
|
|
@@ -1618,8 +2652,9 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1618
2652
|
let bestTagLength = 0;
|
|
1619
2653
|
for (const name of toolNames) {
|
|
1620
2654
|
const openTag = `<${name}>`;
|
|
1621
|
-
const selfTagRegex =
|
|
2655
|
+
const selfTagRegex = getSelfClosingTagPattern2(name);
|
|
1622
2656
|
const idxOpen = buffer.indexOf(openTag);
|
|
2657
|
+
selfTagRegex.lastIndex = 0;
|
|
1623
2658
|
const selfMatch = selfTagRegex.exec(buffer);
|
|
1624
2659
|
const idxSelf = selfMatch ? selfMatch.index : -1;
|
|
1625
2660
|
if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
|
|
@@ -1642,6 +2677,29 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1642
2677
|
tagLength: bestTagLength
|
|
1643
2678
|
};
|
|
1644
2679
|
}
|
|
2680
|
+
function stripTrailingPartialCloseTag(content, toolName) {
|
|
2681
|
+
const closeTag = `</${toolName}>`;
|
|
2682
|
+
const lastLineBreakIndex = Math.max(
|
|
2683
|
+
content.lastIndexOf("\n"),
|
|
2684
|
+
content.lastIndexOf("\r")
|
|
2685
|
+
);
|
|
2686
|
+
const lineStartIndex = lastLineBreakIndex === -1 ? 0 : lastLineBreakIndex + 1;
|
|
2687
|
+
const trailingLine = content.slice(lineStartIndex);
|
|
2688
|
+
const trimmedTrailingLine = trailingLine.trim();
|
|
2689
|
+
if (trimmedTrailingLine.length === 0 || !trimmedTrailingLine.startsWith("</") || trimmedTrailingLine === closeTag || !closeTag.startsWith(trimmedTrailingLine)) {
|
|
2690
|
+
return content;
|
|
2691
|
+
}
|
|
2692
|
+
const leadingWhitespaceLength = trailingLine.length - trailingLine.trimStart().length;
|
|
2693
|
+
const preservedLeadingWhitespace = trailingLine.slice(
|
|
2694
|
+
0,
|
|
2695
|
+
leadingWhitespaceLength
|
|
2696
|
+
);
|
|
2697
|
+
const contentWithoutPartial = `${content.slice(
|
|
2698
|
+
0,
|
|
2699
|
+
lineStartIndex
|
|
2700
|
+
)}${preservedLeadingWhitespace}`;
|
|
2701
|
+
return contentWithoutPartial.trimEnd();
|
|
2702
|
+
}
|
|
1645
2703
|
var yamlProtocol = (_protocolOptions) => {
|
|
1646
2704
|
return {
|
|
1647
2705
|
formatTools({ tools, toolSystemPromptTemplate }) {
|
|
@@ -1702,7 +2760,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1702
2760
|
let currentToolCall = null;
|
|
1703
2761
|
let currentTextId = null;
|
|
1704
2762
|
let hasEmittedTextStart = false;
|
|
1705
|
-
const flushText =
|
|
2763
|
+
const flushText = createFlushTextHandler(
|
|
1706
2764
|
() => currentTextId,
|
|
1707
2765
|
(newId) => {
|
|
1708
2766
|
currentTextId = newId;
|
|
@@ -1712,33 +2770,128 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1712
2770
|
hasEmittedTextStart = value;
|
|
1713
2771
|
}
|
|
1714
2772
|
);
|
|
1715
|
-
const
|
|
2773
|
+
const emitToolInputProgress2 = (controller, toolContent) => {
|
|
2774
|
+
if (!currentToolCall) {
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
const parsedArgs = parseYamlContentForStreamProgress(toolContent);
|
|
2778
|
+
if (parsedArgs === null) {
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2781
|
+
const fullInput = JSON.stringify(parsedArgs);
|
|
2782
|
+
if (fullInput === "{}" && toolContent.trim().length === 0) {
|
|
2783
|
+
return;
|
|
2784
|
+
}
|
|
2785
|
+
const prefixCandidate = toIncompleteJsonPrefix(fullInput);
|
|
2786
|
+
emitPrefixDelta({
|
|
2787
|
+
controller,
|
|
2788
|
+
id: currentToolCall.toolCallId,
|
|
2789
|
+
state: currentToolCall,
|
|
2790
|
+
candidate: prefixCandidate
|
|
2791
|
+
});
|
|
2792
|
+
};
|
|
2793
|
+
const processToolCallEnd = (controller, toolContent, toolName, toolCallId) => {
|
|
1716
2794
|
var _a;
|
|
1717
2795
|
const parsedArgs = parseYamlContent(toolContent, options);
|
|
1718
2796
|
flushText(controller);
|
|
1719
2797
|
if (parsedArgs !== null) {
|
|
2798
|
+
const finalInput = JSON.stringify(parsedArgs);
|
|
2799
|
+
if (currentToolCall && currentToolCall.toolCallId === toolCallId) {
|
|
2800
|
+
emitFinalRemainder({
|
|
2801
|
+
controller,
|
|
2802
|
+
id: toolCallId,
|
|
2803
|
+
state: currentToolCall,
|
|
2804
|
+
finalFullJson: finalInput,
|
|
2805
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
controller.enqueue({
|
|
2809
|
+
type: "tool-input-end",
|
|
2810
|
+
id: toolCallId
|
|
2811
|
+
});
|
|
1720
2812
|
controller.enqueue({
|
|
1721
2813
|
type: "tool-call",
|
|
1722
|
-
toolCallId
|
|
2814
|
+
toolCallId,
|
|
1723
2815
|
toolName,
|
|
1724
|
-
input:
|
|
2816
|
+
input: finalInput
|
|
1725
2817
|
});
|
|
1726
2818
|
} else {
|
|
2819
|
+
controller.enqueue({
|
|
2820
|
+
type: "tool-input-end",
|
|
2821
|
+
id: toolCallId
|
|
2822
|
+
});
|
|
1727
2823
|
const original = `<${toolName}>${toolContent}</${toolName}>`;
|
|
1728
2824
|
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
|
|
1729
2825
|
toolCall: original
|
|
1730
2826
|
});
|
|
1731
|
-
|
|
2827
|
+
if (shouldEmitRawToolCallTextOnError3(options)) {
|
|
2828
|
+
flushText(controller, original);
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
};
|
|
2832
|
+
const finalizeUnclosedToolCall = (controller) => {
|
|
2833
|
+
var _a;
|
|
2834
|
+
if (!currentToolCall) {
|
|
2835
|
+
return;
|
|
2836
|
+
}
|
|
2837
|
+
emitToolInputProgress2(controller, buffer);
|
|
2838
|
+
const { name: toolName, toolCallId } = currentToolCall;
|
|
2839
|
+
const reconciledBuffer = stripTrailingPartialCloseTag(buffer, toolName);
|
|
2840
|
+
const parsedArgs = parseYamlContent(reconciledBuffer, options);
|
|
2841
|
+
flushText(controller);
|
|
2842
|
+
if (parsedArgs !== null) {
|
|
2843
|
+
const finalInput = JSON.stringify(parsedArgs);
|
|
2844
|
+
emitFinalRemainder({
|
|
2845
|
+
controller,
|
|
2846
|
+
id: toolCallId,
|
|
2847
|
+
state: currentToolCall,
|
|
2848
|
+
finalFullJson: finalInput,
|
|
2849
|
+
onMismatch: options == null ? void 0 : options.onError
|
|
2850
|
+
});
|
|
2851
|
+
controller.enqueue({
|
|
2852
|
+
type: "tool-input-end",
|
|
2853
|
+
id: toolCallId
|
|
2854
|
+
});
|
|
2855
|
+
controller.enqueue({
|
|
2856
|
+
type: "tool-call",
|
|
2857
|
+
toolCallId,
|
|
2858
|
+
toolName,
|
|
2859
|
+
input: finalInput
|
|
2860
|
+
});
|
|
2861
|
+
} else {
|
|
2862
|
+
controller.enqueue({
|
|
2863
|
+
type: "tool-input-end",
|
|
2864
|
+
id: toolCallId
|
|
2865
|
+
});
|
|
2866
|
+
const unfinishedContent = `<${toolName}>${buffer}`;
|
|
2867
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
2868
|
+
options,
|
|
2869
|
+
"Could not complete streaming YAML tool call at finish.",
|
|
2870
|
+
{ toolCall: unfinishedContent }
|
|
2871
|
+
);
|
|
2872
|
+
if (shouldEmitRawToolCallTextOnError3(options)) {
|
|
2873
|
+
flushText(controller, unfinishedContent);
|
|
2874
|
+
}
|
|
1732
2875
|
}
|
|
2876
|
+
buffer = "";
|
|
2877
|
+
currentToolCall = null;
|
|
1733
2878
|
};
|
|
1734
2879
|
const handlePendingToolCall = (controller, endTag, toolName) => {
|
|
2880
|
+
var _a;
|
|
1735
2881
|
const endIdx = buffer.indexOf(endTag);
|
|
1736
2882
|
if (endIdx === -1) {
|
|
2883
|
+
emitToolInputProgress2(controller, buffer);
|
|
1737
2884
|
return false;
|
|
1738
2885
|
}
|
|
1739
2886
|
const content = buffer.substring(0, endIdx);
|
|
2887
|
+
emitToolInputProgress2(controller, content);
|
|
1740
2888
|
buffer = buffer.substring(endIdx + endTag.length);
|
|
1741
|
-
processToolCallEnd(
|
|
2889
|
+
processToolCallEnd(
|
|
2890
|
+
controller,
|
|
2891
|
+
content,
|
|
2892
|
+
toolName,
|
|
2893
|
+
(_a = currentToolCall == null ? void 0 : currentToolCall.toolCallId) != null ? _a : generateToolCallId()
|
|
2894
|
+
);
|
|
1742
2895
|
currentToolCall = null;
|
|
1743
2896
|
return true;
|
|
1744
2897
|
};
|
|
@@ -1755,13 +2908,35 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1755
2908
|
if (tagIndex > 0) {
|
|
1756
2909
|
flushText(controller, buffer.substring(0, tagIndex));
|
|
1757
2910
|
}
|
|
2911
|
+
flushText(controller);
|
|
1758
2912
|
if (selfClosing) {
|
|
1759
2913
|
buffer = buffer.substring(tagIndex + tagLength);
|
|
1760
|
-
|
|
2914
|
+
const toolCallId = generateToolCallId();
|
|
2915
|
+
currentToolCall = {
|
|
2916
|
+
name: tagName,
|
|
2917
|
+
toolCallId,
|
|
2918
|
+
emittedInput: ""
|
|
2919
|
+
};
|
|
2920
|
+
controller.enqueue({
|
|
2921
|
+
type: "tool-input-start",
|
|
2922
|
+
id: toolCallId,
|
|
2923
|
+
toolName: tagName
|
|
2924
|
+
});
|
|
2925
|
+
processToolCallEnd(controller, "", tagName, toolCallId);
|
|
2926
|
+
currentToolCall = null;
|
|
1761
2927
|
} else {
|
|
1762
2928
|
const startTag = `<${tagName}>`;
|
|
1763
2929
|
buffer = buffer.substring(tagIndex + startTag.length);
|
|
1764
|
-
currentToolCall = {
|
|
2930
|
+
currentToolCall = {
|
|
2931
|
+
name: tagName,
|
|
2932
|
+
toolCallId: generateToolCallId(),
|
|
2933
|
+
emittedInput: ""
|
|
2934
|
+
};
|
|
2935
|
+
controller.enqueue({
|
|
2936
|
+
type: "tool-input-start",
|
|
2937
|
+
id: currentToolCall.toolCallId,
|
|
2938
|
+
toolName: tagName
|
|
2939
|
+
});
|
|
1765
2940
|
}
|
|
1766
2941
|
};
|
|
1767
2942
|
const processBuffer = (controller) => {
|
|
@@ -1790,10 +2965,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1790
2965
|
var _a;
|
|
1791
2966
|
if (chunk.type === "finish") {
|
|
1792
2967
|
if (currentToolCall) {
|
|
1793
|
-
|
|
1794
|
-
flushText(controller, unfinishedContent);
|
|
1795
|
-
buffer = "";
|
|
1796
|
-
currentToolCall = null;
|
|
2968
|
+
finalizeUnclosedToolCall(controller);
|
|
1797
2969
|
} else if (buffer) {
|
|
1798
2970
|
flushText(controller, buffer);
|
|
1799
2971
|
buffer = "";
|
|
@@ -1803,7 +2975,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1803
2975
|
return;
|
|
1804
2976
|
}
|
|
1805
2977
|
if (chunk.type !== "text-delta") {
|
|
1806
|
-
if (buffer) {
|
|
2978
|
+
if (!currentToolCall && buffer) {
|
|
1807
2979
|
flushText(controller, buffer);
|
|
1808
2980
|
buffer = "";
|
|
1809
2981
|
}
|
|
@@ -1816,10 +2988,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1816
2988
|
},
|
|
1817
2989
|
flush(controller) {
|
|
1818
2990
|
if (currentToolCall) {
|
|
1819
|
-
|
|
1820
|
-
flushText(controller, unfinishedContent);
|
|
1821
|
-
buffer = "";
|
|
1822
|
-
currentToolCall = null;
|
|
2991
|
+
finalizeUnclosedToolCall(controller);
|
|
1823
2992
|
} else if (buffer) {
|
|
1824
2993
|
flushText(controller, buffer);
|
|
1825
2994
|
buffer = "";
|
|
@@ -1997,9 +3166,6 @@ function hasInputProperty(obj) {
|
|
|
1997
3166
|
return typeof obj === "object" && obj !== null && "input" in obj;
|
|
1998
3167
|
}
|
|
1999
3168
|
|
|
2000
|
-
// src/generate-handler.ts
|
|
2001
|
-
import { generateId as generateId2 } from "@ai-sdk/provider-utils";
|
|
2002
|
-
|
|
2003
3169
|
// src/core/utils/generated-text-json-recovery.ts
|
|
2004
3170
|
function isRecord(value) {
|
|
2005
3171
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -2138,7 +3304,7 @@ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
|
|
|
2138
3304
|
function toToolCallPart(candidate) {
|
|
2139
3305
|
return {
|
|
2140
3306
|
type: "tool-call",
|
|
2141
|
-
toolCallId:
|
|
3307
|
+
toolCallId: generateToolCallId(),
|
|
2142
3308
|
toolName: candidate.toolName,
|
|
2143
3309
|
input: candidate.input
|
|
2144
3310
|
};
|
|
@@ -2365,7 +3531,7 @@ async function handleToolChoice(doGenerate, params, tools) {
|
|
|
2365
3531
|
}
|
|
2366
3532
|
const toolCall = {
|
|
2367
3533
|
type: "tool-call",
|
|
2368
|
-
toolCallId:
|
|
3534
|
+
toolCallId: generateToolCallId(),
|
|
2369
3535
|
toolName,
|
|
2370
3536
|
input
|
|
2371
3537
|
};
|
|
@@ -2875,7 +4041,6 @@ unit: celsius
|
|
|
2875
4041
|
}
|
|
2876
4042
|
|
|
2877
4043
|
// src/stream-handler.ts
|
|
2878
|
-
import { generateId as generateId3 } from "@ai-sdk/provider-utils";
|
|
2879
4044
|
async function wrapStream({
|
|
2880
4045
|
protocol,
|
|
2881
4046
|
doStream,
|
|
@@ -2913,10 +4078,22 @@ async function wrapStream({
|
|
|
2913
4078
|
}
|
|
2914
4079
|
)
|
|
2915
4080
|
).pipeThrough(protocol.createStreamParser({ tools, options }));
|
|
4081
|
+
let seenToolCall = false;
|
|
2916
4082
|
const v3Stream = coreStream.pipeThrough(
|
|
2917
4083
|
new TransformStream({
|
|
2918
4084
|
transform(part, controller) {
|
|
2919
|
-
|
|
4085
|
+
let normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
|
|
4086
|
+
if (normalizedPart.type === "tool-call") {
|
|
4087
|
+
seenToolCall = true;
|
|
4088
|
+
}
|
|
4089
|
+
if (normalizedPart.type === "finish" && seenToolCall && normalizedPart.finishReason.unified === "stop") {
|
|
4090
|
+
normalizedPart = {
|
|
4091
|
+
...normalizedPart,
|
|
4092
|
+
finishReason: normalizeToolCallsFinishReason(
|
|
4093
|
+
normalizedPart.finishReason
|
|
4094
|
+
)
|
|
4095
|
+
};
|
|
4096
|
+
}
|
|
2920
4097
|
if (debugLevel === "stream") {
|
|
2921
4098
|
logParsedChunk(normalizedPart);
|
|
2922
4099
|
}
|
|
@@ -2953,7 +4130,7 @@ async function toolChoiceStream({
|
|
|
2953
4130
|
start(controller) {
|
|
2954
4131
|
controller.enqueue({
|
|
2955
4132
|
type: "tool-call",
|
|
2956
|
-
toolCallId:
|
|
4133
|
+
toolCallId: generateToolCallId(),
|
|
2957
4134
|
toolName,
|
|
2958
4135
|
input
|
|
2959
4136
|
});
|
|
@@ -3465,4 +4642,4 @@ export {
|
|
|
3465
4642
|
xmlToolMiddleware,
|
|
3466
4643
|
yamlToolMiddleware
|
|
3467
4644
|
};
|
|
3468
|
-
//# sourceMappingURL=chunk-
|
|
4645
|
+
//# sourceMappingURL=chunk-DPGORNPB.js.map
|