@ai-sdk-tool/parser 3.3.3 → 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-NAQSTPDQ.js → chunk-ERJKQKCR.js} +1372 -205
- package/dist/chunk-ERJKQKCR.js.map +1 -0
- package/dist/community.cjs +1390 -223
- package/dist/community.cjs.map +1 -1
- package/dist/community.js +1 -1
- package/dist/index.cjs +1390 -223
- 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 +1 -1
- package/package.json +7 -7
- package/dist/chunk-NAQSTPDQ.js.map +0 -1
|
@@ -187,7 +187,25 @@ function getPotentialStartIndex(text, searchedText) {
|
|
|
187
187
|
|
|
188
188
|
// src/core/utils/id.ts
|
|
189
189
|
function generateId() {
|
|
190
|
-
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)}`;
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
// src/core/utils/protocol-utils.ts
|
|
@@ -196,17 +214,55 @@ function addTextSegment(text, processedElements) {
|
|
|
196
214
|
processedElements.push({ type: "text", text });
|
|
197
215
|
}
|
|
198
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
|
+
}
|
|
199
249
|
|
|
200
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
|
+
}
|
|
201
257
|
function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
|
|
202
|
-
var _a
|
|
258
|
+
var _a;
|
|
203
259
|
try {
|
|
204
260
|
const parsedToolCall = parse(toolCallJson);
|
|
205
261
|
processedElements.push({
|
|
206
262
|
type: "tool-call",
|
|
207
|
-
toolCallId:
|
|
263
|
+
toolCallId: generateToolCallId(),
|
|
208
264
|
toolName: parsedToolCall.name,
|
|
209
|
-
input:
|
|
265
|
+
input: canonicalizeToolInput(parsedToolCall.arguments)
|
|
210
266
|
});
|
|
211
267
|
} catch (error) {
|
|
212
268
|
logParseFailure({
|
|
@@ -215,7 +271,7 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
|
|
|
215
271
|
snippet: fullMatch,
|
|
216
272
|
error
|
|
217
273
|
});
|
|
218
|
-
(
|
|
274
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
|
|
219
275
|
options,
|
|
220
276
|
"Could not process JSON tool call, keeping original text.",
|
|
221
277
|
{ toolCall: fullMatch, error }
|
|
@@ -236,6 +292,293 @@ function processMatchedToolCall(context) {
|
|
|
236
292
|
}
|
|
237
293
|
return startIndex + match[0].length;
|
|
238
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
|
+
}
|
|
239
582
|
function flushBuffer(state, controller, toolCallStart) {
|
|
240
583
|
if (state.buffer.length === 0) {
|
|
241
584
|
return;
|
|
@@ -266,44 +609,77 @@ function closeTextBlock(state, controller) {
|
|
|
266
609
|
state.hasEmittedTextStart = false;
|
|
267
610
|
}
|
|
268
611
|
}
|
|
269
|
-
function emitIncompleteToolCall(state, controller, toolCallStart) {
|
|
270
|
-
|
|
612
|
+
function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, options) {
|
|
613
|
+
var _a;
|
|
614
|
+
if (!state.currentToolCallJson && trailingBuffer.length === 0) {
|
|
615
|
+
state.isInsideToolCall = false;
|
|
271
616
|
return;
|
|
272
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);
|
|
273
631
|
logParseFailure({
|
|
274
632
|
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
|
|
633
|
+
reason: shouldEmitRawFallback ? "Incomplete streaming tool call segment emitted as text" : "Incomplete streaming tool call segment suppressed without raw text fallback",
|
|
634
|
+
snippet: errorContent
|
|
292
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
|
+
);
|
|
293
658
|
state.currentToolCallJson = "";
|
|
659
|
+
state.isInsideToolCall = false;
|
|
294
660
|
}
|
|
295
|
-
function handleFinishChunk(state, controller, toolCallStart, chunk) {
|
|
296
|
-
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) {
|
|
297
673
|
flushBuffer(state, controller, toolCallStart);
|
|
298
674
|
}
|
|
299
675
|
closeTextBlock(state, controller);
|
|
300
|
-
emitIncompleteToolCall(state, controller, toolCallStart);
|
|
301
676
|
controller.enqueue(chunk);
|
|
302
677
|
}
|
|
303
678
|
function publishText(text, state, controller) {
|
|
304
679
|
if (state.isInsideToolCall) {
|
|
305
680
|
closeTextBlock(state, controller);
|
|
306
681
|
state.currentToolCallJson += text;
|
|
682
|
+
emitToolInputProgress(state, controller);
|
|
307
683
|
} else if (text.length > 0) {
|
|
308
684
|
if (!state.currentTextId) {
|
|
309
685
|
state.currentTextId = generateId();
|
|
@@ -321,42 +697,40 @@ function publishText(text, state, controller) {
|
|
|
321
697
|
}
|
|
322
698
|
}
|
|
323
699
|
function emitToolCall(context) {
|
|
324
|
-
var _a
|
|
700
|
+
var _a;
|
|
325
701
|
const { state, controller, toolCallStart, toolCallEnd, options } = context;
|
|
326
702
|
try {
|
|
327
703
|
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
|
-
});
|
|
704
|
+
emitToolCallFromParsed(state, controller, parsedToolCall);
|
|
335
705
|
} catch (error) {
|
|
706
|
+
const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
|
|
707
|
+
const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
|
|
336
708
|
logParseFailure({
|
|
337
709
|
phase: "stream",
|
|
338
710
|
reason: "Failed to parse streaming tool call JSON segment",
|
|
339
|
-
snippet:
|
|
711
|
+
snippet: errorContent,
|
|
340
712
|
error
|
|
341
713
|
});
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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(
|
|
358
732
|
options,
|
|
359
|
-
"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.",
|
|
360
734
|
{
|
|
361
735
|
toolCall: errorContent
|
|
362
736
|
}
|
|
@@ -372,6 +746,7 @@ function processTagMatch(context) {
|
|
|
372
746
|
} else {
|
|
373
747
|
state.currentToolCallJson = "";
|
|
374
748
|
state.isInsideToolCall = true;
|
|
749
|
+
state.activeToolInput = null;
|
|
375
750
|
}
|
|
376
751
|
}
|
|
377
752
|
function processBufferTags(context) {
|
|
@@ -394,8 +769,16 @@ function processBufferTags(context) {
|
|
|
394
769
|
);
|
|
395
770
|
}
|
|
396
771
|
}
|
|
397
|
-
function handlePartialTag(state, controller, toolCallStart) {
|
|
772
|
+
function handlePartialTag(state, controller, toolCallStart, toolCallEnd) {
|
|
398
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
|
+
}
|
|
399
782
|
return;
|
|
400
783
|
}
|
|
401
784
|
const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
|
|
@@ -468,13 +851,14 @@ var jsonProtocol = ({
|
|
|
468
851
|
buffer: "",
|
|
469
852
|
currentToolCallJson: "",
|
|
470
853
|
currentTextId: null,
|
|
471
|
-
hasEmittedTextStart: false
|
|
854
|
+
hasEmittedTextStart: false,
|
|
855
|
+
activeToolInput: null
|
|
472
856
|
};
|
|
473
857
|
return new TransformStream({
|
|
474
858
|
transform(chunk, controller) {
|
|
475
859
|
var _a;
|
|
476
860
|
if (chunk.type === "finish") {
|
|
477
|
-
handleFinishChunk(state, controller, toolCallStart, chunk);
|
|
861
|
+
handleFinishChunk(state, controller, toolCallStart, options, chunk);
|
|
478
862
|
return;
|
|
479
863
|
}
|
|
480
864
|
if (chunk.type !== "text-delta") {
|
|
@@ -490,7 +874,7 @@ var jsonProtocol = ({
|
|
|
490
874
|
toolCallEnd,
|
|
491
875
|
options
|
|
492
876
|
});
|
|
493
|
-
handlePartialTag(state, controller, toolCallStart);
|
|
877
|
+
handlePartialTag(state, controller, toolCallStart, toolCallEnd);
|
|
494
878
|
}
|
|
495
879
|
});
|
|
496
880
|
},
|
|
@@ -520,6 +904,80 @@ function isTCMProtocolFactory(protocol) {
|
|
|
520
904
|
var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
|
|
521
905
|
var WHITESPACE_REGEX = /\s/;
|
|
522
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
|
+
|
|
523
981
|
// src/core/utils/xml-root-repair.ts
|
|
524
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*$/;
|
|
525
983
|
function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
|
|
@@ -549,6 +1007,9 @@ function getToolSchema(tools, toolName) {
|
|
|
549
1007
|
var _a;
|
|
550
1008
|
return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
|
|
551
1009
|
}
|
|
1010
|
+
function shouldEmitRawToolCallTextOnError2(options) {
|
|
1011
|
+
return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
|
|
1012
|
+
}
|
|
552
1013
|
function processToolCall(params) {
|
|
553
1014
|
var _a, _b;
|
|
554
1015
|
const { toolCall, tools, options, text, processedElements, parseOptions } = params;
|
|
@@ -561,7 +1022,7 @@ function processToolCall(params) {
|
|
|
561
1022
|
const parsed = parse2(toolCall.content, toolSchema, parseConfig);
|
|
562
1023
|
processedElements.push({
|
|
563
1024
|
type: "tool-call",
|
|
564
|
-
toolCallId:
|
|
1025
|
+
toolCallId: generateToolCallId(),
|
|
565
1026
|
toolName: toolCall.toolName,
|
|
566
1027
|
input: JSON.stringify(parsed)
|
|
567
1028
|
});
|
|
@@ -578,6 +1039,299 @@ function processToolCall(params) {
|
|
|
578
1039
|
processedElements.push({ type: "text", text: originalCallText });
|
|
579
1040
|
}
|
|
580
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
|
+
}
|
|
581
1335
|
function handleStreamingToolCallEnd(params) {
|
|
582
1336
|
var _a, _b;
|
|
583
1337
|
const {
|
|
@@ -597,19 +1351,37 @@ function handleStreamingToolCallEnd(params) {
|
|
|
597
1351
|
flushText(ctrl);
|
|
598
1352
|
try {
|
|
599
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
|
+
});
|
|
600
1366
|
ctrl.enqueue({
|
|
601
1367
|
type: "tool-call",
|
|
602
|
-
toolCallId:
|
|
1368
|
+
toolCallId: currentToolCall.toolCallId,
|
|
603
1369
|
toolName: currentToolCall.name,
|
|
604
|
-
input:
|
|
1370
|
+
input: finalInput
|
|
605
1371
|
});
|
|
606
1372
|
} catch (error) {
|
|
1373
|
+
ctrl.enqueue({
|
|
1374
|
+
type: "tool-input-end",
|
|
1375
|
+
id: currentToolCall.toolCallId
|
|
1376
|
+
});
|
|
607
1377
|
const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
|
|
608
1378
|
(_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
|
|
609
1379
|
toolCall: original,
|
|
610
1380
|
error
|
|
611
1381
|
});
|
|
612
|
-
|
|
1382
|
+
if (shouldEmitRawToolCallTextOnError2(options)) {
|
|
1383
|
+
flushText(ctrl, original);
|
|
1384
|
+
}
|
|
613
1385
|
}
|
|
614
1386
|
}
|
|
615
1387
|
function findClosingTagEndFlexible(text, contentStart, toolName) {
|
|
@@ -1031,38 +1803,6 @@ function findPotentialToolTagStart(buffer, toolNames) {
|
|
|
1031
1803
|
}
|
|
1032
1804
|
return -1;
|
|
1033
1805
|
}
|
|
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
1806
|
function processToolCallInBuffer(params) {
|
|
1067
1807
|
const {
|
|
1068
1808
|
buffer,
|
|
@@ -1072,18 +1812,21 @@ function processToolCallInBuffer(params) {
|
|
|
1072
1812
|
controller,
|
|
1073
1813
|
flushText,
|
|
1074
1814
|
setBuffer,
|
|
1075
|
-
parseOptions
|
|
1815
|
+
parseOptions,
|
|
1816
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
1076
1817
|
} = params;
|
|
1077
1818
|
const endTagPattern = new RegExp(
|
|
1078
1819
|
`</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
|
|
1079
1820
|
);
|
|
1080
1821
|
const endMatch = endTagPattern.exec(buffer);
|
|
1081
1822
|
if (!endMatch || endMatch.index === void 0) {
|
|
1823
|
+
emitToolInputProgress2(controller, currentToolCall, buffer);
|
|
1082
1824
|
return { buffer, currentToolCall, shouldBreak: true };
|
|
1083
1825
|
}
|
|
1084
1826
|
const endIdx = endMatch.index;
|
|
1085
1827
|
const endPos = endIdx + endMatch[0].length;
|
|
1086
1828
|
const content = buffer.substring(0, endIdx);
|
|
1829
|
+
emitToolInputProgress2(controller, currentToolCall, content);
|
|
1087
1830
|
const remainder = buffer.substring(endPos);
|
|
1088
1831
|
setBuffer(remainder);
|
|
1089
1832
|
handleStreamingToolCallEnd({
|
|
@@ -1110,7 +1853,8 @@ function processNoToolCallInBuffer(params) {
|
|
|
1110
1853
|
tools,
|
|
1111
1854
|
options,
|
|
1112
1855
|
parseOptions,
|
|
1113
|
-
setBuffer
|
|
1856
|
+
setBuffer,
|
|
1857
|
+
emitToolInputStart
|
|
1114
1858
|
} = params;
|
|
1115
1859
|
const {
|
|
1116
1860
|
index: earliestStartTagIndex,
|
|
@@ -1140,9 +1884,10 @@ function processNoToolCallInBuffer(params) {
|
|
|
1140
1884
|
if (selfClosing) {
|
|
1141
1885
|
const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
|
|
1142
1886
|
setBuffer(newBuffer2);
|
|
1887
|
+
const currentToolCall = emitToolInputStart(controller, earliestToolName);
|
|
1143
1888
|
handleStreamingToolCallEnd({
|
|
1144
1889
|
toolContent: "",
|
|
1145
|
-
currentToolCall
|
|
1890
|
+
currentToolCall,
|
|
1146
1891
|
tools,
|
|
1147
1892
|
options,
|
|
1148
1893
|
ctrl: controller,
|
|
@@ -1161,12 +1906,12 @@ function processNoToolCallInBuffer(params) {
|
|
|
1161
1906
|
setBuffer(newBuffer);
|
|
1162
1907
|
return {
|
|
1163
1908
|
buffer: newBuffer,
|
|
1164
|
-
currentToolCall:
|
|
1909
|
+
currentToolCall: emitToolInputStart(controller, earliestToolName),
|
|
1165
1910
|
shouldBreak: false,
|
|
1166
1911
|
shouldContinue: true
|
|
1167
1912
|
};
|
|
1168
1913
|
}
|
|
1169
|
-
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) {
|
|
1170
1915
|
return (controller) => {
|
|
1171
1916
|
while (true) {
|
|
1172
1917
|
const currentToolCall = getCurrentToolCall();
|
|
@@ -1179,7 +1924,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1179
1924
|
controller,
|
|
1180
1925
|
flushText,
|
|
1181
1926
|
setBuffer,
|
|
1182
|
-
parseOptions
|
|
1927
|
+
parseOptions,
|
|
1928
|
+
emitToolInputProgress: emitToolInputProgress2
|
|
1183
1929
|
});
|
|
1184
1930
|
setBuffer(result.buffer);
|
|
1185
1931
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1195,7 +1941,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
|
|
|
1195
1941
|
tools,
|
|
1196
1942
|
options,
|
|
1197
1943
|
parseOptions,
|
|
1198
|
-
setBuffer
|
|
1944
|
+
setBuffer,
|
|
1945
|
+
emitToolInputStart
|
|
1199
1946
|
});
|
|
1200
1947
|
setBuffer(result.buffer);
|
|
1201
1948
|
setCurrentToolCall(result.currentToolCall);
|
|
@@ -1308,7 +2055,119 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1308
2055
|
(value) => {
|
|
1309
2056
|
hasEmittedTextStart = value;
|
|
1310
2057
|
}
|
|
1311
|
-
);
|
|
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
|
+
};
|
|
1312
2171
|
const processBuffer = createProcessBufferHandler(
|
|
1313
2172
|
() => buffer,
|
|
1314
2173
|
(newBuffer) => {
|
|
@@ -1322,17 +2181,17 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1322
2181
|
options,
|
|
1323
2182
|
toolNames,
|
|
1324
2183
|
flushText,
|
|
1325
|
-
parseOptions
|
|
2184
|
+
parseOptions,
|
|
2185
|
+
emitToolInputProgress2,
|
|
2186
|
+
emitToolInputStart
|
|
1326
2187
|
);
|
|
1327
2188
|
return new TransformStream({
|
|
2189
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Stateful stream parsing requires branching over chunk lifecycle and parser states.
|
|
1328
2190
|
transform(chunk, controller) {
|
|
1329
2191
|
var _a2;
|
|
1330
2192
|
if (chunk.type === "finish") {
|
|
1331
2193
|
if (currentToolCall) {
|
|
1332
|
-
|
|
1333
|
-
flushText(controller, unfinishedContent);
|
|
1334
|
-
buffer = "";
|
|
1335
|
-
currentToolCall = null;
|
|
2194
|
+
finalizeUnclosedToolCall(controller);
|
|
1336
2195
|
} else if (buffer) {
|
|
1337
2196
|
flushText(controller, buffer);
|
|
1338
2197
|
buffer = "";
|
|
@@ -1342,7 +2201,8 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1342
2201
|
return;
|
|
1343
2202
|
}
|
|
1344
2203
|
if (chunk.type !== "text-delta") {
|
|
1345
|
-
if (
|
|
2204
|
+
if (currentToolCall) {
|
|
2205
|
+
} else if (buffer) {
|
|
1346
2206
|
flushText(controller, buffer);
|
|
1347
2207
|
buffer = "";
|
|
1348
2208
|
}
|
|
@@ -1355,10 +2215,7 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1355
2215
|
},
|
|
1356
2216
|
flush(controller) {
|
|
1357
2217
|
if (currentToolCall) {
|
|
1358
|
-
|
|
1359
|
-
flushText(controller, unfinishedContent);
|
|
1360
|
-
buffer = "";
|
|
1361
|
-
currentToolCall = null;
|
|
2218
|
+
finalizeUnclosedToolCall(controller);
|
|
1362
2219
|
} else if (buffer) {
|
|
1363
2220
|
flushText(controller, buffer);
|
|
1364
2221
|
buffer = "";
|
|
@@ -1386,7 +2243,205 @@ var xmlProtocol = (protocolOptions) => {
|
|
|
1386
2243
|
|
|
1387
2244
|
// src/core/protocols/yaml-protocol.ts
|
|
1388
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
|
+
}
|
|
1389
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
|
+
}
|
|
1390
2445
|
function findClosingTagEnd(text, contentStart, toolName) {
|
|
1391
2446
|
let pos = contentStart;
|
|
1392
2447
|
let depth = 1;
|
|
@@ -1458,7 +2513,7 @@ function findEarliestTagPosition(openIdx, selfIdx) {
|
|
|
1458
2513
|
function collectToolCallsForName(text, toolName) {
|
|
1459
2514
|
const toolCalls = [];
|
|
1460
2515
|
let searchIndex = 0;
|
|
1461
|
-
const selfTagRegex =
|
|
2516
|
+
const selfTagRegex = getSelfClosingTagPattern2(toolName);
|
|
1462
2517
|
while (searchIndex < text.length) {
|
|
1463
2518
|
const startTag = `<${toolName}>`;
|
|
1464
2519
|
const openIdx = text.indexOf(startTag, searchIndex);
|
|
@@ -1510,47 +2565,48 @@ function findToolCalls2(text, toolNames) {
|
|
|
1510
2565
|
return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
|
|
1511
2566
|
}
|
|
1512
2567
|
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);
|
|
2568
|
+
var _a, _b;
|
|
2569
|
+
const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
|
|
1520
2570
|
if (nonEmptyLines.length === 0) {
|
|
1521
2571
|
return {};
|
|
1522
2572
|
}
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
})
|
|
1528
|
-
|
|
1529
|
-
if (minIndent > 0) {
|
|
1530
|
-
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;
|
|
1531
2579
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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);
|
|
1539
2601
|
}
|
|
1540
|
-
const
|
|
1541
|
-
if (
|
|
1542
|
-
return
|
|
2602
|
+
const truncated = dropLastMeaningfulLine(candidate);
|
|
2603
|
+
if (truncated == null) {
|
|
2604
|
+
return null;
|
|
1543
2605
|
}
|
|
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
|
-
});
|
|
2606
|
+
if (truncated === candidate) {
|
|
1548
2607
|
return null;
|
|
1549
2608
|
}
|
|
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;
|
|
2609
|
+
candidate = truncated;
|
|
1554
2610
|
}
|
|
1555
2611
|
}
|
|
1556
2612
|
function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
|
|
@@ -1566,7 +2622,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1566
2622
|
if (parsedArgs !== null) {
|
|
1567
2623
|
processedElements.push({
|
|
1568
2624
|
type: "tool-call",
|
|
1569
|
-
toolCallId:
|
|
2625
|
+
toolCallId: generateToolCallId(),
|
|
1570
2626
|
toolName: tc.toolName,
|
|
1571
2627
|
input: JSON.stringify(parsedArgs)
|
|
1572
2628
|
});
|
|
@@ -1579,38 +2635,6 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
|
|
|
1579
2635
|
}
|
|
1580
2636
|
return tc.endIndex;
|
|
1581
2637
|
}
|
|
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
2638
|
function findEarliestToolTag2(buffer, toolNames) {
|
|
1615
2639
|
let bestIndex = -1;
|
|
1616
2640
|
let bestName = "";
|
|
@@ -1618,8 +2642,9 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1618
2642
|
let bestTagLength = 0;
|
|
1619
2643
|
for (const name of toolNames) {
|
|
1620
2644
|
const openTag = `<${name}>`;
|
|
1621
|
-
const selfTagRegex =
|
|
2645
|
+
const selfTagRegex = getSelfClosingTagPattern2(name);
|
|
1622
2646
|
const idxOpen = buffer.indexOf(openTag);
|
|
2647
|
+
selfTagRegex.lastIndex = 0;
|
|
1623
2648
|
const selfMatch = selfTagRegex.exec(buffer);
|
|
1624
2649
|
const idxSelf = selfMatch ? selfMatch.index : -1;
|
|
1625
2650
|
if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
|
|
@@ -1642,6 +2667,29 @@ function findEarliestToolTag2(buffer, toolNames) {
|
|
|
1642
2667
|
tagLength: bestTagLength
|
|
1643
2668
|
};
|
|
1644
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
|
+
}
|
|
1645
2693
|
var yamlProtocol = (_protocolOptions) => {
|
|
1646
2694
|
return {
|
|
1647
2695
|
formatTools({ tools, toolSystemPromptTemplate }) {
|
|
@@ -1702,7 +2750,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1702
2750
|
let currentToolCall = null;
|
|
1703
2751
|
let currentTextId = null;
|
|
1704
2752
|
let hasEmittedTextStart = false;
|
|
1705
|
-
const flushText =
|
|
2753
|
+
const flushText = createFlushTextHandler(
|
|
1706
2754
|
() => currentTextId,
|
|
1707
2755
|
(newId) => {
|
|
1708
2756
|
currentTextId = newId;
|
|
@@ -1712,33 +2760,128 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1712
2760
|
hasEmittedTextStart = value;
|
|
1713
2761
|
}
|
|
1714
2762
|
);
|
|
1715
|
-
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) => {
|
|
1716
2784
|
var _a;
|
|
1717
2785
|
const parsedArgs = parseYamlContent(toolContent, options);
|
|
1718
2786
|
flushText(controller);
|
|
1719
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
|
+
});
|
|
1720
2802
|
controller.enqueue({
|
|
1721
2803
|
type: "tool-call",
|
|
1722
|
-
toolCallId
|
|
2804
|
+
toolCallId,
|
|
1723
2805
|
toolName,
|
|
1724
|
-
input:
|
|
2806
|
+
input: finalInput
|
|
1725
2807
|
});
|
|
1726
2808
|
} else {
|
|
2809
|
+
controller.enqueue({
|
|
2810
|
+
type: "tool-input-end",
|
|
2811
|
+
id: toolCallId
|
|
2812
|
+
});
|
|
1727
2813
|
const original = `<${toolName}>${toolContent}</${toolName}>`;
|
|
1728
2814
|
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
|
|
1729
2815
|
toolCall: original
|
|
1730
2816
|
});
|
|
1731
|
-
|
|
2817
|
+
if (shouldEmitRawToolCallTextOnError3(options)) {
|
|
2818
|
+
flushText(controller, original);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
const finalizeUnclosedToolCall = (controller) => {
|
|
2823
|
+
var _a;
|
|
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);
|
|
2831
|
+
flushText(controller);
|
|
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
|
+
});
|
|
2845
|
+
controller.enqueue({
|
|
2846
|
+
type: "tool-call",
|
|
2847
|
+
toolCallId,
|
|
2848
|
+
toolName,
|
|
2849
|
+
input: finalInput
|
|
2850
|
+
});
|
|
2851
|
+
} else {
|
|
2852
|
+
controller.enqueue({
|
|
2853
|
+
type: "tool-input-end",
|
|
2854
|
+
id: toolCallId
|
|
2855
|
+
});
|
|
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
|
+
}
|
|
1732
2865
|
}
|
|
2866
|
+
buffer = "";
|
|
2867
|
+
currentToolCall = null;
|
|
1733
2868
|
};
|
|
1734
2869
|
const handlePendingToolCall = (controller, endTag, toolName) => {
|
|
2870
|
+
var _a;
|
|
1735
2871
|
const endIdx = buffer.indexOf(endTag);
|
|
1736
2872
|
if (endIdx === -1) {
|
|
2873
|
+
emitToolInputProgress2(controller, buffer);
|
|
1737
2874
|
return false;
|
|
1738
2875
|
}
|
|
1739
2876
|
const content = buffer.substring(0, endIdx);
|
|
2877
|
+
emitToolInputProgress2(controller, content);
|
|
1740
2878
|
buffer = buffer.substring(endIdx + endTag.length);
|
|
1741
|
-
processToolCallEnd(
|
|
2879
|
+
processToolCallEnd(
|
|
2880
|
+
controller,
|
|
2881
|
+
content,
|
|
2882
|
+
toolName,
|
|
2883
|
+
(_a = currentToolCall == null ? void 0 : currentToolCall.toolCallId) != null ? _a : generateToolCallId()
|
|
2884
|
+
);
|
|
1742
2885
|
currentToolCall = null;
|
|
1743
2886
|
return true;
|
|
1744
2887
|
};
|
|
@@ -1755,13 +2898,35 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1755
2898
|
if (tagIndex > 0) {
|
|
1756
2899
|
flushText(controller, buffer.substring(0, tagIndex));
|
|
1757
2900
|
}
|
|
2901
|
+
flushText(controller);
|
|
1758
2902
|
if (selfClosing) {
|
|
1759
2903
|
buffer = buffer.substring(tagIndex + tagLength);
|
|
1760
|
-
|
|
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;
|
|
1761
2917
|
} else {
|
|
1762
2918
|
const startTag = `<${tagName}>`;
|
|
1763
2919
|
buffer = buffer.substring(tagIndex + startTag.length);
|
|
1764
|
-
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
|
+
});
|
|
1765
2930
|
}
|
|
1766
2931
|
};
|
|
1767
2932
|
const processBuffer = (controller) => {
|
|
@@ -1790,10 +2955,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1790
2955
|
var _a;
|
|
1791
2956
|
if (chunk.type === "finish") {
|
|
1792
2957
|
if (currentToolCall) {
|
|
1793
|
-
|
|
1794
|
-
flushText(controller, unfinishedContent);
|
|
1795
|
-
buffer = "";
|
|
1796
|
-
currentToolCall = null;
|
|
2958
|
+
finalizeUnclosedToolCall(controller);
|
|
1797
2959
|
} else if (buffer) {
|
|
1798
2960
|
flushText(controller, buffer);
|
|
1799
2961
|
buffer = "";
|
|
@@ -1803,7 +2965,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1803
2965
|
return;
|
|
1804
2966
|
}
|
|
1805
2967
|
if (chunk.type !== "text-delta") {
|
|
1806
|
-
if (buffer) {
|
|
2968
|
+
if (!currentToolCall && buffer) {
|
|
1807
2969
|
flushText(controller, buffer);
|
|
1808
2970
|
buffer = "";
|
|
1809
2971
|
}
|
|
@@ -1816,10 +2978,7 @@ ${yamlContent}</${toolCall.toolName}>`;
|
|
|
1816
2978
|
},
|
|
1817
2979
|
flush(controller) {
|
|
1818
2980
|
if (currentToolCall) {
|
|
1819
|
-
|
|
1820
|
-
flushText(controller, unfinishedContent);
|
|
1821
|
-
buffer = "";
|
|
1822
|
-
currentToolCall = null;
|
|
2981
|
+
finalizeUnclosedToolCall(controller);
|
|
1823
2982
|
} else if (buffer) {
|
|
1824
2983
|
flushText(controller, buffer);
|
|
1825
2984
|
buffer = "";
|
|
@@ -1997,9 +3156,6 @@ function hasInputProperty(obj) {
|
|
|
1997
3156
|
return typeof obj === "object" && obj !== null && "input" in obj;
|
|
1998
3157
|
}
|
|
1999
3158
|
|
|
2000
|
-
// src/generate-handler.ts
|
|
2001
|
-
import { generateId as generateId2 } from "@ai-sdk/provider-utils";
|
|
2002
|
-
|
|
2003
3159
|
// src/core/utils/generated-text-json-recovery.ts
|
|
2004
3160
|
function isRecord(value) {
|
|
2005
3161
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -2138,7 +3294,7 @@ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
|
|
|
2138
3294
|
function toToolCallPart(candidate) {
|
|
2139
3295
|
return {
|
|
2140
3296
|
type: "tool-call",
|
|
2141
|
-
toolCallId:
|
|
3297
|
+
toolCallId: generateToolCallId(),
|
|
2142
3298
|
toolName: candidate.toolName,
|
|
2143
3299
|
input: candidate.input
|
|
2144
3300
|
};
|
|
@@ -2365,7 +3521,7 @@ async function handleToolChoice(doGenerate, params, tools) {
|
|
|
2365
3521
|
}
|
|
2366
3522
|
const toolCall = {
|
|
2367
3523
|
type: "tool-call",
|
|
2368
|
-
toolCallId:
|
|
3524
|
+
toolCallId: generateToolCallId(),
|
|
2369
3525
|
toolName,
|
|
2370
3526
|
input
|
|
2371
3527
|
};
|
|
@@ -2875,7 +4031,6 @@ unit: celsius
|
|
|
2875
4031
|
}
|
|
2876
4032
|
|
|
2877
4033
|
// src/stream-handler.ts
|
|
2878
|
-
import { generateId as generateId3 } from "@ai-sdk/provider-utils";
|
|
2879
4034
|
async function wrapStream({
|
|
2880
4035
|
protocol,
|
|
2881
4036
|
doStream,
|
|
@@ -2913,10 +4068,22 @@ async function wrapStream({
|
|
|
2913
4068
|
}
|
|
2914
4069
|
)
|
|
2915
4070
|
).pipeThrough(protocol.createStreamParser({ tools, options }));
|
|
4071
|
+
let seenToolCall = false;
|
|
2916
4072
|
const v3Stream = coreStream.pipeThrough(
|
|
2917
4073
|
new TransformStream({
|
|
2918
4074
|
transform(part, controller) {
|
|
2919
|
-
|
|
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
|
+
}
|
|
2920
4087
|
if (debugLevel === "stream") {
|
|
2921
4088
|
logParsedChunk(normalizedPart);
|
|
2922
4089
|
}
|
|
@@ -2953,7 +4120,7 @@ async function toolChoiceStream({
|
|
|
2953
4120
|
start(controller) {
|
|
2954
4121
|
controller.enqueue({
|
|
2955
4122
|
type: "tool-call",
|
|
2956
|
-
toolCallId:
|
|
4123
|
+
toolCallId: generateToolCallId(),
|
|
2957
4124
|
toolName,
|
|
2958
4125
|
input
|
|
2959
4126
|
});
|
|
@@ -3465,4 +4632,4 @@ export {
|
|
|
3465
4632
|
xmlToolMiddleware,
|
|
3466
4633
|
yamlToolMiddleware
|
|
3467
4634
|
};
|
|
3468
|
-
//# sourceMappingURL=chunk-
|
|
4635
|
+
//# sourceMappingURL=chunk-ERJKQKCR.js.map
|