@ai-sdk-tool/parser 4.1.19 → 4.1.21

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.
@@ -4645,13 +4645,312 @@ function shouldEmitRawToolCallTextOnError(options) {
4645
4645
  }
4646
4646
 
4647
4647
  // src/core/protocols/hermes-protocol.ts
4648
+ var RJSON_IDENTIFIER_CHAR_REGEX = /[$a-zA-Z0-9_\-+.*?!|&%^/#\\]/;
4649
+ var RJSON_NUMBER_TOKEN_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
4650
+ function validateNonEmptyDelimiters(toolCallStart, toolCallEnd) {
4651
+ if (toolCallStart.length === 0) {
4652
+ throw new TypeError("hermesProtocol toolCallStart must not be empty");
4653
+ }
4654
+ if (toolCallEnd.length === 0) {
4655
+ throw new TypeError("hermesProtocol toolCallEnd must not be empty");
4656
+ }
4657
+ return {};
4658
+ }
4659
+ function isRjsonIdentifierChar(ch) {
4660
+ return ch != null && RJSON_IDENTIFIER_CHAR_REGEX.test(ch);
4661
+ }
4662
+ function isRjsonPropertyLikeDelimiter(startTag) {
4663
+ const key = startTag.endsWith(":") ? startTag.slice(0, -1) : "";
4664
+ return key.length > 0 && [...key].every((ch) => isRjsonIdentifierChar(ch));
4665
+ }
4666
+ function previousRjsonToken(json, index, minIndex = 0) {
4667
+ let start = index - 1;
4668
+ while (start >= minIndex && isRjsonIdentifierChar(json[start])) {
4669
+ start -= 1;
4670
+ }
4671
+ return json.slice(start + 1, index);
4672
+ }
4673
+ function previousTokenAllowsComment(json, index, minIndex = 0) {
4674
+ const previous = previousRjsonToken(json, index, minIndex);
4675
+ if (previous.length === 0) {
4676
+ return true;
4677
+ }
4678
+ return RJSON_NUMBER_TOKEN_REGEX.test(previous) || previous === "true" || previous === "false" || previous === "null";
4679
+ }
4680
+ function startsRjsonComment(json, index, minIndex = 0) {
4681
+ if (!(json[index] === "/" && json[index + 1] === "/" || json[index] === "/" && json[index + 1] === "*")) {
4682
+ return false;
4683
+ }
4684
+ if (index > minIndex && isRjsonIdentifierChar(json[index - 1])) {
4685
+ return previousTokenAllowsComment(json, index, minIndex);
4686
+ }
4687
+ return true;
4688
+ }
4689
+ function hasNestedStartBoundary(segment, startIndex) {
4690
+ const previous = segment[startIndex - 1];
4691
+ return previous == null || WHITESPACE_JSON_REGEX.test(previous) || previous === "}";
4692
+ }
4693
+ function isLikelyNestedToolCallStart(segment, startIndex, startTag) {
4694
+ if (isRjsonPropertyLikeDelimiter(startTag)) {
4695
+ return false;
4696
+ }
4697
+ const jsonStart = skipJsonWhitespace(segment, startIndex + startTag.length);
4698
+ return segment[jsonStart] === "{" && hasNestedStartBoundary(segment, startIndex);
4699
+ }
4700
+ function findToolCallBoundaryOutsideRjsonSyntax(text, scanFrom, startTag, endTag) {
4701
+ let quote = null;
4702
+ let esc = false;
4703
+ let inLineComment = false;
4704
+ let inBlockComment = false;
4705
+ let lineCommentSawEndTag = false;
4706
+ let blockCommentSawEndTag = false;
4707
+ let nestedStartIndex = null;
4708
+ for (let index = scanFrom; index < text.length; index += 1) {
4709
+ const ch = text[index];
4710
+ if (esc) {
4711
+ esc = false;
4712
+ continue;
4713
+ }
4714
+ if (quote !== null) {
4715
+ if (ch === "\\") {
4716
+ esc = true;
4717
+ continue;
4718
+ }
4719
+ if (ch === quote) {
4720
+ quote = null;
4721
+ }
4722
+ continue;
4723
+ }
4724
+ if (inLineComment) {
4725
+ if (ch === "\n" || ch === "\r") {
4726
+ inLineComment = false;
4727
+ lineCommentSawEndTag = false;
4728
+ continue;
4729
+ }
4730
+ if (text.startsWith(endTag, index)) {
4731
+ lineCommentSawEndTag = true;
4732
+ index += endTag.length - 1;
4733
+ continue;
4734
+ }
4735
+ if (lineCommentSawEndTag && text.startsWith(startTag, index) && text[skipJsonWhitespace(text, index + startTag.length)] === "{") {
4736
+ nestedStartIndex = index;
4737
+ inLineComment = false;
4738
+ lineCommentSawEndTag = false;
4739
+ index += startTag.length - 1;
4740
+ continue;
4741
+ }
4742
+ continue;
4743
+ }
4744
+ if (inBlockComment) {
4745
+ if (ch === "*" && text[index + 1] === "/") {
4746
+ inBlockComment = false;
4747
+ blockCommentSawEndTag = false;
4748
+ index += 1;
4749
+ continue;
4750
+ }
4751
+ if (text.startsWith(endTag, index)) {
4752
+ blockCommentSawEndTag = true;
4753
+ index += endTag.length - 1;
4754
+ continue;
4755
+ }
4756
+ if (blockCommentSawEndTag && text.startsWith(startTag, index) && text[skipJsonWhitespace(text, index + startTag.length)] === "{") {
4757
+ nestedStartIndex = index;
4758
+ inBlockComment = false;
4759
+ blockCommentSawEndTag = false;
4760
+ index += startTag.length - 1;
4761
+ continue;
4762
+ }
4763
+ continue;
4764
+ }
4765
+ if (startsRjsonComment(text, index, scanFrom)) {
4766
+ if (text[index + 1] === "/") {
4767
+ inLineComment = true;
4768
+ lineCommentSawEndTag = false;
4769
+ index += 1;
4770
+ continue;
4771
+ }
4772
+ if (text[index + 1] === "*") {
4773
+ inBlockComment = true;
4774
+ blockCommentSawEndTag = false;
4775
+ index += 1;
4776
+ continue;
4777
+ }
4778
+ }
4779
+ if (text.startsWith(endTag, index)) {
4780
+ return nestedStartIndex == null ? { kind: "end", endIdx: index } : { kind: "nested", endIdx: index, nestedStartIndex };
4781
+ }
4782
+ if (nestedStartIndex == null && text.startsWith(startTag, index) && isLikelyNestedToolCallStart(text, index, startTag)) {
4783
+ nestedStartIndex = index;
4784
+ index += startTag.length - 1;
4785
+ continue;
4786
+ }
4787
+ if (ch === '"' || ch === "'") {
4788
+ quote = ch;
4789
+ }
4790
+ }
4791
+ return null;
4792
+ }
4793
+ function findNextToolCallSpan(text, searchFrom, startTag, endTag) {
4794
+ const startIdx = text.indexOf(startTag, searchFrom);
4795
+ if (startIdx === -1) {
4796
+ return null;
4797
+ }
4798
+ const jsonStart = startIdx + startTag.length;
4799
+ const boundary = findToolCallBoundaryOutsideRjsonSyntax(
4800
+ text,
4801
+ jsonStart,
4802
+ startTag,
4803
+ endTag
4804
+ );
4805
+ if (boundary == null) {
4806
+ return { startIdx, found: false };
4807
+ }
4808
+ if (boundary.kind === "nested") {
4809
+ return { startIdx, found: false };
4810
+ }
4811
+ return { startIdx, found: true, jsonStart, endIdx: boundary.endIdx };
4812
+ }
4648
4813
  function canonicalizeToolInput(argumentsValue) {
4649
4814
  return JSON.stringify(argumentsValue != null ? argumentsValue : {});
4650
4815
  }
4816
+ var CHAR_CODE_BACKSLASH = 92;
4817
+ var CHAR_CODE_QUOTE = 34;
4818
+ var CHAR_CODE_LF = 10;
4819
+ var CHAR_CODE_CR = 13;
4820
+ var CHAR_CODE_TAB = 9;
4821
+ var CHAR_CODE_SLASH = 47;
4822
+ var CHAR_CODE_STAR = 42;
4823
+ var CHAR_CODE_CONTROL_UPPER = 31;
4824
+ var CHAR_CODE_SINGLE_QUOTE = 39;
4825
+ function hasControlCharInString(json) {
4826
+ let quote = null;
4827
+ let esc = false;
4828
+ for (let i = 0; i < json.length; i += 1) {
4829
+ const code = json.charCodeAt(i);
4830
+ if (esc) {
4831
+ esc = false;
4832
+ if (code <= CHAR_CODE_CONTROL_UPPER) {
4833
+ return true;
4834
+ }
4835
+ continue;
4836
+ }
4837
+ if (quote !== null && code === CHAR_CODE_BACKSLASH) {
4838
+ esc = true;
4839
+ continue;
4840
+ }
4841
+ if (quote !== null) {
4842
+ if (code === quote) {
4843
+ quote = null;
4844
+ continue;
4845
+ }
4846
+ if (code <= CHAR_CODE_CONTROL_UPPER) {
4847
+ return true;
4848
+ }
4849
+ continue;
4850
+ }
4851
+ if (code === CHAR_CODE_SLASH && json.charCodeAt(i + 1) === CHAR_CODE_SLASH) {
4852
+ i += 2;
4853
+ while (i < json.length && json.charCodeAt(i) !== CHAR_CODE_LF && json.charCodeAt(i) !== CHAR_CODE_CR) {
4854
+ i += 1;
4855
+ }
4856
+ continue;
4857
+ }
4858
+ if (code === CHAR_CODE_SLASH && json.charCodeAt(i + 1) === CHAR_CODE_STAR) {
4859
+ i += 2;
4860
+ while (i + 1 < json.length && !(json.charCodeAt(i) === CHAR_CODE_STAR && json.charCodeAt(i + 1) === CHAR_CODE_SLASH)) {
4861
+ i += 1;
4862
+ }
4863
+ i += 1;
4864
+ continue;
4865
+ }
4866
+ if (code === CHAR_CODE_QUOTE || code === CHAR_CODE_SINGLE_QUOTE) {
4867
+ quote = code;
4868
+ }
4869
+ }
4870
+ return false;
4871
+ }
4872
+ function normalizeJsonStringCtrl(json) {
4873
+ if (!hasControlCharInString(json)) {
4874
+ return json;
4875
+ }
4876
+ const parts = [];
4877
+ let chunkStart = 0;
4878
+ let quote = null;
4879
+ let esc = false;
4880
+ const flushUpTo = (end) => {
4881
+ if (chunkStart < end) {
4882
+ parts.push(json.slice(chunkStart, end));
4883
+ }
4884
+ };
4885
+ const escapeForCode = (code) => {
4886
+ switch (code) {
4887
+ case CHAR_CODE_LF:
4888
+ return "\\n";
4889
+ case CHAR_CODE_CR:
4890
+ return "\\r";
4891
+ case CHAR_CODE_TAB:
4892
+ return "\\t";
4893
+ default:
4894
+ return `\\u${code.toString(16).padStart(4, "0")}`;
4895
+ }
4896
+ };
4897
+ for (let i = 0; i < json.length; i += 1) {
4898
+ const code = json.charCodeAt(i);
4899
+ if (esc) {
4900
+ esc = false;
4901
+ if (code <= CHAR_CODE_CONTROL_UPPER) {
4902
+ flushUpTo(i - 1);
4903
+ parts.push(escapeForCode(code));
4904
+ chunkStart = i + 1;
4905
+ }
4906
+ continue;
4907
+ }
4908
+ if (quote !== null && code === CHAR_CODE_BACKSLASH) {
4909
+ esc = true;
4910
+ continue;
4911
+ }
4912
+ if (quote !== null) {
4913
+ if (code === quote) {
4914
+ quote = null;
4915
+ continue;
4916
+ }
4917
+ if (code <= CHAR_CODE_CONTROL_UPPER) {
4918
+ flushUpTo(i);
4919
+ parts.push(escapeForCode(code));
4920
+ chunkStart = i + 1;
4921
+ }
4922
+ continue;
4923
+ }
4924
+ if (code === CHAR_CODE_SLASH && json.charCodeAt(i + 1) === CHAR_CODE_SLASH) {
4925
+ i += 2;
4926
+ while (i < json.length && json.charCodeAt(i) !== CHAR_CODE_LF && json.charCodeAt(i) !== CHAR_CODE_CR) {
4927
+ i += 1;
4928
+ }
4929
+ continue;
4930
+ }
4931
+ if (code === CHAR_CODE_SLASH && json.charCodeAt(i + 1) === CHAR_CODE_STAR) {
4932
+ i += 2;
4933
+ while (i + 1 < json.length && !(json.charCodeAt(i) === CHAR_CODE_STAR && json.charCodeAt(i + 1) === CHAR_CODE_SLASH)) {
4934
+ i += 1;
4935
+ }
4936
+ i += 1;
4937
+ continue;
4938
+ }
4939
+ if (code === CHAR_CODE_QUOTE || code === CHAR_CODE_SINGLE_QUOTE) {
4940
+ quote = code;
4941
+ }
4942
+ }
4943
+ if (chunkStart < json.length) {
4944
+ parts.push(json.slice(chunkStart));
4945
+ }
4946
+ return parts.join("");
4947
+ }
4651
4948
  function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
4652
4949
  var _a;
4653
4950
  try {
4654
- const parsedToolCall = parse3(toolCallJson);
4951
+ const parsedToolCall = parse3(
4952
+ normalizeJsonStringCtrl(toolCallJson)
4953
+ );
4655
4954
  processedElements.push({
4656
4955
  type: "tool-call",
4657
4956
  toolCallId: generateToolCallId(),
@@ -4659,6 +4958,8 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
4659
4958
  input: canonicalizeToolInput(parsedToolCall.arguments)
4660
4959
  });
4661
4960
  } catch (error) {
4961
+ const salvagedToolName = extractStreamingToolCallProgress(toolCallJson).toolName;
4962
+ const salvagedToolCallId = generateToolCallId();
4662
4963
  logParseFailure({
4663
4964
  phase: "generated-text",
4664
4965
  reason: "Failed to parse tool call JSON segment",
@@ -4668,24 +4969,17 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
4668
4969
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
4669
4970
  options,
4670
4971
  "Could not process JSON tool call, keeping original text.",
4671
- { toolCall: fullMatch, error }
4972
+ {
4973
+ toolCall: fullMatch,
4974
+ error,
4975
+ toolName: salvagedToolName,
4976
+ toolCallId: salvagedToolCallId,
4977
+ dropReason: "malformed-tool-call-body"
4978
+ }
4672
4979
  );
4673
4980
  processedElements.push({ type: "text", text: fullMatch });
4674
4981
  }
4675
4982
  }
4676
- function processMatchedToolCall(context) {
4677
- const { match, text, currentIndex, processedElements, options } = context;
4678
- const startIndex = match.index;
4679
- const toolCallJson = match[1];
4680
- if (startIndex > currentIndex) {
4681
- const textSegment = text.slice(currentIndex, startIndex);
4682
- addTextSegment(textSegment, processedElements);
4683
- }
4684
- if (toolCallJson) {
4685
- processToolCallJson(toolCallJson, match[0], processedElements, options);
4686
- }
4687
- return startIndex + match[0].length;
4688
- }
4689
4983
  var WHITESPACE_JSON_REGEX = /\s/;
4690
4984
  function skipJsonWhitespace(text, fromIndex) {
4691
4985
  let index = fromIndex;
@@ -4952,7 +5246,9 @@ function canonicalizeArgumentsProgressInput(progress, toolName, tools) {
4952
5246
  return void 0;
4953
5247
  }
4954
5248
  try {
4955
- const parsedArguments = parse3(progress.argumentsText);
5249
+ const parsedArguments = parse3(
5250
+ normalizeJsonStringCtrl(progress.argumentsText)
5251
+ );
4956
5252
  return stringifyToolInputWithSchema({
4957
5253
  toolName,
4958
5254
  args: parsedArguments,
@@ -5012,14 +5308,16 @@ function closeTextBlock(state, controller) {
5012
5308
  }
5013
5309
  }
5014
5310
  function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, tools, options) {
5015
- var _a;
5311
+ var _a, _b, _c, _d;
5016
5312
  if (!state.currentToolCallJson && trailingBuffer.length === 0) {
5017
5313
  state.isInsideToolCall = false;
5018
5314
  return;
5019
5315
  }
5020
5316
  if (state.currentToolCallJson) {
5021
5317
  try {
5022
- const parsedToolCall = parse3(state.currentToolCallJson);
5318
+ const parsedToolCall = parse3(
5319
+ normalizeJsonStringCtrl(state.currentToolCallJson)
5320
+ );
5023
5321
  emitToolCallFromParsed(state, controller, parsedToolCall, tools);
5024
5322
  state.currentToolCallJson = "";
5025
5323
  state.isInsideToolCall = false;
@@ -5051,11 +5349,19 @@ function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer
5051
5349
  id: errorId
5052
5350
  });
5053
5351
  }
5352
+ const streamingToolCallId = (_b = (_a = state.activeToolInput) == null ? void 0 : _a.id) != null ? _b : generateToolCallId();
5353
+ const streamingToolName = (_c = state.activeToolInput) == null ? void 0 : _c.toolName;
5054
5354
  closeToolInput(state, controller);
5055
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5355
+ const toolName = streamingToolName != null ? streamingToolName : state.currentToolCallJson ? extractStreamingToolCallProgress(state.currentToolCallJson).toolName : void 0;
5356
+ (_d = options == null ? void 0 : options.onError) == null ? void 0 : _d.call(
5056
5357
  options,
5057
5358
  shouldEmitRawFallback ? "Could not complete streaming JSON tool call at finish; emitting original text." : "Could not complete streaming JSON tool call at finish.",
5058
- { toolCall: errorContent }
5359
+ {
5360
+ toolCall: errorContent,
5361
+ toolCallId: streamingToolCallId,
5362
+ toolName,
5363
+ dropReason: "unfinished-tool-call"
5364
+ }
5059
5365
  );
5060
5366
  state.currentToolCallJson = "";
5061
5367
  state.isInsideToolCall = false;
@@ -5100,14 +5406,18 @@ function publishText(text, state, controller, tools) {
5100
5406
  }
5101
5407
  }
5102
5408
  function emitToolCall(context) {
5103
- var _a;
5409
+ var _a, _b, _c, _d, _e;
5104
5410
  const { state, controller, toolCallStart, toolCallEnd, options, tools } = context;
5105
5411
  try {
5106
- const parsedToolCall = parse3(state.currentToolCallJson);
5412
+ const parsedToolCall = parse3(
5413
+ normalizeJsonStringCtrl(state.currentToolCallJson)
5414
+ );
5107
5415
  emitToolCallFromParsed(state, controller, parsedToolCall, tools);
5108
5416
  } catch (error) {
5109
5417
  const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
5110
5418
  const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
5419
+ const streamingToolCallId = (_b = (_a = state.activeToolInput) == null ? void 0 : _a.id) != null ? _b : generateToolCallId();
5420
+ const streamingToolName = (_d = (_c = state.activeToolInput) == null ? void 0 : _c.toolName) != null ? _d : extractStreamingToolCallProgress(state.currentToolCallJson).toolName;
5111
5421
  logParseFailure({
5112
5422
  phase: "stream",
5113
5423
  reason: "Failed to parse streaming tool call JSON segment",
@@ -5131,11 +5441,15 @@ function emitToolCall(context) {
5131
5441
  });
5132
5442
  }
5133
5443
  closeToolInput(state, controller);
5134
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5444
+ (_e = options == null ? void 0 : options.onError) == null ? void 0 : _e.call(
5135
5445
  options,
5136
5446
  shouldEmitRawFallback ? "Could not process streaming JSON tool call; emitting original text." : "Could not process streaming JSON tool call.",
5137
5447
  {
5138
- toolCall: errorContent
5448
+ toolCall: errorContent,
5449
+ error,
5450
+ toolCallId: streamingToolCallId,
5451
+ toolName: streamingToolName,
5452
+ dropReason: "malformed-tool-call-body"
5139
5453
  }
5140
5454
  );
5141
5455
  }
@@ -5152,24 +5466,118 @@ function processTagMatch(context) {
5152
5466
  state.activeToolInput = null;
5153
5467
  }
5154
5468
  }
5155
- function processBufferTags(context) {
5469
+ function recoverNestedStreamingToolCall(options) {
5470
+ var _a, _b, _c, _d;
5471
+ const { context, jsonSoFar, nestedStartIndex, startIndex, tag } = options;
5472
+ const {
5473
+ state,
5474
+ controller,
5475
+ toolCallStart,
5476
+ toolCallEnd,
5477
+ options: parserOptions
5478
+ } = context;
5479
+ const droppedToolCall = `${toolCallStart}${jsonSoFar.slice(
5480
+ 0,
5481
+ nestedStartIndex
5482
+ )}`;
5483
+ const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(parserOptions);
5484
+ const streamingToolCallId = (_a = state.activeToolInput) == null ? void 0 : _a.id;
5485
+ const streamingToolName = (_c = (_b = state.activeToolInput) == null ? void 0 : _b.toolName) != null ? _c : extractStreamingToolCallProgress(jsonSoFar.slice(0, nestedStartIndex)).toolName;
5486
+ logParseFailure({
5487
+ phase: "stream",
5488
+ reason: "Abandoning malformed streaming tool call before nested start tag",
5489
+ snippet: droppedToolCall
5490
+ });
5491
+ if (shouldEmitRawFallback) {
5492
+ const errorId = generateId();
5493
+ controller.enqueue({
5494
+ type: "text-start",
5495
+ id: errorId
5496
+ });
5497
+ controller.enqueue({
5498
+ type: "text-delta",
5499
+ id: errorId,
5500
+ delta: droppedToolCall
5501
+ });
5502
+ controller.enqueue({
5503
+ type: "text-end",
5504
+ id: errorId
5505
+ });
5506
+ }
5507
+ closeToolInput(state, controller);
5508
+ (_d = parserOptions == null ? void 0 : parserOptions.onError) == null ? void 0 : _d.call(
5509
+ parserOptions,
5510
+ shouldEmitRawFallback ? "Could not process malformed streaming JSON tool call before nested start; emitting original text." : "Could not process malformed streaming JSON tool call before nested start.",
5511
+ {
5512
+ toolCall: droppedToolCall,
5513
+ toolCallId: streamingToolCallId,
5514
+ toolName: streamingToolName,
5515
+ dropReason: "malformed-nested-tool-call"
5516
+ }
5517
+ );
5518
+ state.currentToolCallJson = "";
5519
+ state.isInsideToolCall = false;
5520
+ state.buffer = jsonSoFar.slice(nestedStartIndex) + toolCallEnd + state.buffer.slice(startIndex + tag.length);
5521
+ return getPotentialStartIndex(state.buffer, toolCallStart);
5522
+ }
5523
+ function processInsideToolCallBoundary(context) {
5156
5524
  const { state, controller, toolCallStart, toolCallEnd, tools } = context;
5157
- let startIndex = getPotentialStartIndex(
5158
- state.buffer,
5159
- state.isInsideToolCall ? toolCallEnd : toolCallStart
5525
+ const currentLength = state.currentToolCallJson.length;
5526
+ const combined = state.currentToolCallJson + state.buffer;
5527
+ const boundary = findToolCallBoundaryOutsideRjsonSyntax(
5528
+ combined,
5529
+ 0,
5530
+ toolCallStart,
5531
+ toolCallEnd
5532
+ );
5533
+ if (boundary == null) {
5534
+ return false;
5535
+ }
5536
+ const relativeEndIndex = boundary.endIdx - currentLength;
5537
+ if (relativeEndIndex < 0) {
5538
+ return false;
5539
+ }
5540
+ if (boundary.kind === "nested") {
5541
+ recoverNestedStreamingToolCall({
5542
+ context,
5543
+ jsonSoFar: combined.slice(0, boundary.endIdx),
5544
+ nestedStartIndex: boundary.nestedStartIndex,
5545
+ startIndex: relativeEndIndex,
5546
+ tag: toolCallEnd
5547
+ });
5548
+ return true;
5549
+ }
5550
+ publishText(
5551
+ state.buffer.slice(0, relativeEndIndex),
5552
+ state,
5553
+ controller,
5554
+ tools
5160
5555
  );
5556
+ state.buffer = state.buffer.slice(relativeEndIndex + toolCallEnd.length);
5557
+ processTagMatch(context);
5558
+ return true;
5559
+ }
5560
+ function processBufferTags(context) {
5561
+ const { state, controller, toolCallStart, tools } = context;
5562
+ while (state.isInsideToolCall) {
5563
+ if (!processInsideToolCallBoundary(context)) {
5564
+ return;
5565
+ }
5566
+ }
5567
+ let startIndex = getPotentialStartIndex(state.buffer, toolCallStart);
5161
5568
  while (startIndex != null) {
5162
- const tag = state.isInsideToolCall ? toolCallEnd : toolCallStart;
5163
- if (startIndex + tag.length > state.buffer.length) {
5569
+ if (startIndex + toolCallStart.length > state.buffer.length) {
5164
5570
  break;
5165
5571
  }
5166
5572
  publishText(state.buffer.slice(0, startIndex), state, controller, tools);
5167
- state.buffer = state.buffer.slice(startIndex + tag.length);
5573
+ state.buffer = state.buffer.slice(startIndex + toolCallStart.length);
5168
5574
  processTagMatch(context);
5169
- startIndex = getPotentialStartIndex(
5170
- state.buffer,
5171
- state.isInsideToolCall ? toolCallEnd : toolCallStart
5172
- );
5575
+ while (state.isInsideToolCall) {
5576
+ if (!processInsideToolCallBoundary(context)) {
5577
+ return;
5578
+ }
5579
+ }
5580
+ startIndex = getPotentialStartIndex(state.buffer, toolCallStart);
5173
5581
  }
5174
5582
  }
5175
5583
  function handlePartialTag(state, controller, toolCallStart, toolCallEnd, tools) {
@@ -5207,6 +5615,7 @@ var hermesProtocol = ({
5207
5615
  toolCallStart = "<tool_call>",
5208
5616
  toolCallEnd = "</tool_call>"
5209
5617
  } = {}) => ({
5618
+ ...validateNonEmptyDelimiters(toolCallStart, toolCallEnd),
5210
5619
  formatTools({
5211
5620
  tools,
5212
5621
  toolSystemPromptTemplate
@@ -5231,24 +5640,42 @@ var hermesProtocol = ({
5231
5640
  text,
5232
5641
  options
5233
5642
  }) {
5234
- const startEsc = escapeRegExp(toolCallStart);
5235
- const endEsc = escapeRegExp(toolCallEnd);
5236
- const toolCallRegex = new RegExp(
5237
- `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
5238
- "gs"
5239
- );
5240
5643
  const processedElements = [];
5241
5644
  let currentIndex = 0;
5242
- let match = toolCallRegex.exec(text);
5243
- while (match !== null) {
5244
- currentIndex = processMatchedToolCall({
5245
- match,
5645
+ let searchFrom = 0;
5646
+ while (searchFrom < text.length) {
5647
+ const span = findNextToolCallSpan(
5246
5648
  text,
5247
- currentIndex,
5248
- processedElements,
5249
- options
5250
- });
5251
- match = toolCallRegex.exec(text);
5649
+ searchFrom,
5650
+ toolCallStart,
5651
+ toolCallEnd
5652
+ );
5653
+ if (span === null) {
5654
+ break;
5655
+ }
5656
+ if (!span.found) {
5657
+ const skipTo = span.startIdx + toolCallStart.length;
5658
+ if (skipTo > currentIndex) {
5659
+ addTextSegment(text.slice(currentIndex, skipTo), processedElements);
5660
+ currentIndex = skipTo;
5661
+ }
5662
+ searchFrom = skipTo;
5663
+ continue;
5664
+ }
5665
+ const toolCallJson = text.slice(span.jsonStart, span.endIdx);
5666
+ const fullMatch = text.slice(
5667
+ span.startIdx,
5668
+ span.endIdx + toolCallEnd.length
5669
+ );
5670
+ if (span.startIdx > currentIndex) {
5671
+ addTextSegment(
5672
+ text.slice(currentIndex, span.startIdx),
5673
+ processedElements
5674
+ );
5675
+ }
5676
+ processToolCallJson(toolCallJson, fullMatch, processedElements, options);
5677
+ currentIndex = span.endIdx + toolCallEnd.length;
5678
+ searchFrom = currentIndex;
5252
5679
  }
5253
5680
  if (currentIndex < text.length) {
5254
5681
  const remainingText = text.slice(currentIndex);
@@ -5301,14 +5728,26 @@ var hermesProtocol = ({
5301
5728
  });
5302
5729
  },
5303
5730
  extractToolCallSegments({ text }) {
5304
- const startEsc = escapeRegExp(toolCallStart);
5305
- const endEsc = escapeRegExp(toolCallEnd);
5306
- const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
5307
5731
  const segments = [];
5308
- let m = regex.exec(text);
5309
- while (m != null) {
5310
- segments.push(m[0]);
5311
- m = regex.exec(text);
5732
+ let searchFrom = 0;
5733
+ while (searchFrom < text.length) {
5734
+ const span = findNextToolCallSpan(
5735
+ text,
5736
+ searchFrom,
5737
+ toolCallStart,
5738
+ toolCallEnd
5739
+ );
5740
+ if (span === null) {
5741
+ break;
5742
+ }
5743
+ if (!span.found) {
5744
+ searchFrom = span.startIdx + toolCallStart.length;
5745
+ continue;
5746
+ }
5747
+ segments.push(
5748
+ text.slice(span.startIdx, span.endIdx + toolCallEnd.length)
5749
+ );
5750
+ searchFrom = span.endIdx + toolCallEnd.length;
5312
5751
  }
5313
5752
  return segments;
5314
5753
  }
@@ -5597,7 +6036,13 @@ function processToolCall(params) {
5597
6036
  (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5598
6037
  options,
5599
6038
  `Could not process XML tool call: ${toolCall.toolName}`,
5600
- { toolCall: originalCallText, error }
6039
+ {
6040
+ toolCall: originalCallText,
6041
+ error,
6042
+ toolName: toolCall.toolName,
6043
+ toolCallId: generateToolCallId(),
6044
+ dropReason: "malformed-tool-call-body"
6045
+ }
5601
6046
  );
5602
6047
  processedElements.push({ type: "text", text: originalCallText });
5603
6048
  }
@@ -6039,7 +6484,10 @@ function handleStreamingToolCallEnd(params) {
6039
6484
  });
6040
6485
  (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
6041
6486
  toolCall: original,
6042
- error
6487
+ error,
6488
+ toolName: currentToolCall.name,
6489
+ toolCallId: currentToolCall.toolCallId,
6490
+ dropReason: "malformed-tool-call-body"
6043
6491
  });
6044
6492
  }
6045
6493
  }
@@ -6601,7 +7049,13 @@ var morphXmlProtocol = (protocolOptions) => {
6601
7049
  (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
6602
7050
  options,
6603
7051
  "Could not complete streaming XML tool call at finish.",
6604
- { toolCall: unfinishedContent, error }
7052
+ {
7053
+ toolCall: unfinishedContent,
7054
+ toolCallId: currentToolCall.toolCallId,
7055
+ toolName: currentToolCall.name,
7056
+ dropReason: "unfinished-tool-call",
7057
+ error
7058
+ }
6605
7059
  );
6606
7060
  }
6607
7061
  buffer = "";
@@ -6827,7 +7281,8 @@ var QWEN3CODER_TOOL_PARSER_CALL_TAG_NAMES = /* @__PURE__ */ new Set([
6827
7281
  "invoke",
6828
7282
  "tool_call"
6829
7283
  ]);
6830
- var CALL_SHORTHAND_VALUE_RE = /^<\s*(call|function|tool|invoke)\b\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>/]+))/i;
7284
+ var CALL_SHORTHAND_VALUE_RE = /^<\s*(call|function|tool|invoke)\b\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>/<]+))/i;
7285
+ var NESTED_CALL_SHORTHAND_VALUE_RE = /<\s*(?:call|function|tool|invoke)\b\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>/<]+))/i;
6831
7286
  var QWEN3CODER_TOOL_PARSER_STREAM_CALL_OPEN_START_RE = /<\s*(?!\/)\s*(call|function|tool|invoke)\b/i;
6832
7287
  var QWEN3CODER_TOOL_PARSER_STREAM_CALL_OPEN_TAG_RE = /<\s*(?!\/)\s*(call|function|tool|invoke)\b[^>]*>/i;
6833
7288
  var QWEN3CODER_TOOL_PARSER_STREAM_TOOL_CALL_CLOSE_TAG_RE = /<\s*\/\s*tool_call\s*>/i;
@@ -7226,6 +7681,12 @@ function getShorthandValue(openTag) {
7226
7681
  }
7227
7682
  return unescapeXml(value);
7228
7683
  }
7684
+ function extractShorthandToolNameFromRaw(rawText) {
7685
+ var _a, _b;
7686
+ const match = NESTED_CALL_SHORTHAND_VALUE_RE.exec(rawText);
7687
+ const value = (_b = (_a = match == null ? void 0 : match[1]) != null ? _a : match == null ? void 0 : match[2]) != null ? _b : match == null ? void 0 : match[3];
7688
+ return value ? unescapeXml(value) : null;
7689
+ }
7229
7690
  function extractFirstTagText(xml, tagName) {
7230
7691
  var _a;
7231
7692
  const lower = xml.toLowerCase();
@@ -7547,6 +8008,20 @@ function parseQwen3CoderToolParserClosedMatches(inner, outerNameAttr) {
7547
8008
  }
7548
8009
  return closedCalls.concat(trailingCalls);
7549
8010
  }
8011
+ var QWEN3CODER_TOOL_NAME_SALVAGE_REGEX = /<(?:function|call|tool|invoke)(?:\s*=\s*"([^"]+)"|\s*=\s*'([^']+)'|\s*=\s*([^\s>/]+)|\s+name\s*=\s*"([^"]+)"|\s+name\s*=\s*'([^']+)')|<(?:name|tool_name)\b[^>]*>([\s\S]*?)<\s*\/\s*(?:name|tool_name)\s*>/i;
8012
+ function extractQwen3CoderToolNameFromMarkup(markup) {
8013
+ var _a, _b, _c, _d, _e;
8014
+ const match = markup.match(QWEN3CODER_TOOL_NAME_SALVAGE_REGEX);
8015
+ if (!match) {
8016
+ return void 0;
8017
+ }
8018
+ const name = (_e = (_d = (_c = (_b = (_a = match[1]) != null ? _a : match[2]) != null ? _b : match[3]) != null ? _c : match[4]) != null ? _d : match[5]) != null ? _e : match[6];
8019
+ if (!name) {
8020
+ return void 0;
8021
+ }
8022
+ const trimmed = name.trim();
8023
+ return trimmed.length > 0 ? trimmed : void 0;
8024
+ }
7550
8025
  function parseQwen3CoderToolParserToolCallSegment(segment) {
7551
8026
  var _a;
7552
8027
  const extracted = extractToolCallInnerXml(segment);
@@ -7671,7 +8146,12 @@ var qwen3CoderProtocol = () => ({
7671
8146
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
7672
8147
  options,
7673
8148
  "Could not process Qwen3CoderToolParser XML tool call; keeping original text.",
7674
- { toolCall: fallbackText }
8149
+ {
8150
+ toolCall: fallbackText,
8151
+ toolName: extractQwen3CoderToolNameFromMarkup(segment),
8152
+ toolCallId: generateToolCallId(),
8153
+ dropReason: "malformed-tool-call-body"
8154
+ }
7675
8155
  );
7676
8156
  processedElements.push({ type: "text", text: fallbackText });
7677
8157
  return false;
@@ -7684,7 +8164,12 @@ var qwen3CoderProtocol = () => ({
7684
8164
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
7685
8165
  options,
7686
8166
  "Could not process Qwen3CoderToolParser <function> call; keeping original text.",
7687
- { toolCall: raw }
8167
+ {
8168
+ toolCall: raw,
8169
+ toolName: extractQwen3CoderToolNameFromMarkup(raw),
8170
+ toolCallId: generateToolCallId(),
8171
+ dropReason: "malformed-tool-call-body"
8172
+ }
7688
8173
  );
7689
8174
  processedElements.push({ type: "text", text: raw });
7690
8175
  };
@@ -7934,7 +8419,7 @@ var qwen3CoderProtocol = () => ({
7934
8419
  });
7935
8420
  };
7936
8421
  const finalizeCall = (controller, callState, fallbackToolName, rawToolCallText = null) => {
7937
- var _a, _b;
8422
+ var _a, _b, _c, _d;
7938
8423
  const resolvedToolName = (_a = callState.toolName) != null ? _a : fallbackToolName;
7939
8424
  if (!resolvedToolName || resolvedToolName.trim().length === 0) {
7940
8425
  const shouldEmitRaw = shouldEmitRawToolCallTextOnError(options);
@@ -7948,12 +8433,14 @@ var qwen3CoderProtocol = () => ({
7948
8433
  flushText(controller, rawText);
7949
8434
  }
7950
8435
  });
7951
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
8436
+ (_d = options == null ? void 0 : options.onError) == null ? void 0 : _d.call(
7952
8437
  options,
7953
8438
  shouldEmitRaw && rawToolCallText ? "Could not resolve Qwen3CoderToolParser tool name for tool call; emitting original text." : "Could not resolve Qwen3CoderToolParser tool name for tool call",
7954
8439
  {
7955
8440
  toolCallId: callState.toolCallId,
7956
- toolCall: rawToolCallText
8441
+ toolCall: rawToolCallText,
8442
+ toolName: (_c = (_b = callState.toolName) != null ? _b : fallbackToolName) != null ? _c : void 0,
8443
+ dropReason: "unresolved-tool-name"
7957
8444
  }
7958
8445
  );
7959
8446
  return false;
@@ -8409,25 +8896,36 @@ var qwen3CoderProtocol = () => ({
8409
8896
  }
8410
8897
  }
8411
8898
  };
8412
- const reportUnfinishedToolCallAtFinish = (controller, rawToolCall) => {
8413
- var _a;
8899
+ const reportUnfinishedToolCallAtFinish = (controller, rawToolCall, metadata = {}) => {
8900
+ var _a, _b;
8414
8901
  const shouldEmitRaw = shouldEmitRawToolCallTextOnError(options);
8415
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
8902
+ const toolName = (_a = metadata.toolName) != null ? _a : extractShorthandToolNameFromRaw(rawToolCall);
8903
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
8416
8904
  options,
8417
8905
  shouldEmitRaw ? "Could not complete streaming Qwen3CoderToolParser XML tool call at finish; emitting original text." : "Could not complete streaming Qwen3CoderToolParser XML tool call at finish.",
8418
- { toolCall: rawToolCall }
8906
+ {
8907
+ toolCall: rawToolCall,
8908
+ ...metadata.toolCallId ? { toolCallId: metadata.toolCallId } : {},
8909
+ ...toolName ? { toolName } : {},
8910
+ dropReason: "unfinished-tool-call"
8911
+ }
8419
8912
  );
8420
8913
  if (shouldEmitRaw) {
8421
8914
  flushText(controller, rawToolCall);
8422
8915
  }
8423
8916
  };
8424
- const reportUnfinishedImplicitCallAtFinish = (controller, rawCallText) => {
8917
+ const reportUnfinishedImplicitCallAtFinish = (controller, rawCallText, callState) => {
8425
8918
  var _a;
8426
8919
  const shouldEmitRaw = shouldEmitRawToolCallTextOnError(options);
8427
8920
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
8428
8921
  options,
8429
8922
  shouldEmitRaw ? "Could not complete streaming Qwen3CoderToolParser call block at finish; emitting original text." : "Could not complete streaming Qwen3CoderToolParser call block at finish.",
8430
- { toolCall: rawCallText }
8923
+ {
8924
+ toolCall: rawCallText,
8925
+ toolCallId: callState.toolCallId,
8926
+ ...callState.toolName ? { toolName: callState.toolName } : {},
8927
+ dropReason: "unfinished-tool-call"
8928
+ }
8431
8929
  );
8432
8930
  if (shouldEmitRaw) {
8433
8931
  flushText(controller, rawCallText);
@@ -8478,7 +8976,10 @@ var qwen3CoderProtocol = () => ({
8478
8976
  flushText(controller, result.trailingText);
8479
8977
  }
8480
8978
  if (!result.ok && toolCall.emittedToolCallCount === 0) {
8481
- reportUnfinishedToolCallAtFinish(controller, toolCall.raw);
8979
+ reportUnfinishedToolCallAtFinish(controller, toolCall.raw, {
8980
+ toolCallId: toolCall.activeCall.toolCallId,
8981
+ ...toolCall.activeCall.toolName ? { toolName: toolCall.activeCall.toolName } : {}
8982
+ });
8482
8983
  }
8483
8984
  } else if (toolCall.mode === "multi") {
8484
8985
  if (toolCall.activeCall) {
@@ -8495,14 +8996,21 @@ var qwen3CoderProtocol = () => ({
8495
8996
  flushText(controller, result.trailingText);
8496
8997
  }
8497
8998
  if (!result.ok && toolCall.emittedToolCallCount === 0) {
8498
- reportUnfinishedToolCallAtFinish(controller, toolCall.raw);
8999
+ reportUnfinishedToolCallAtFinish(controller, toolCall.raw, {
9000
+ toolCallId: toolCall.activeCall.toolCallId,
9001
+ ...toolCall.activeCall.toolName ? { toolName: toolCall.activeCall.toolName } : {}
9002
+ });
8499
9003
  }
8500
9004
  toolCall.activeCall = null;
8501
9005
  } else if (toolCall.emittedToolCallCount === 0) {
8502
- reportUnfinishedToolCallAtFinish(controller, toolCall.raw);
9006
+ reportUnfinishedToolCallAtFinish(controller, toolCall.raw, {
9007
+ toolName: toolCall.outerNameAttr
9008
+ });
8503
9009
  }
8504
9010
  } else {
8505
- reportUnfinishedToolCallAtFinish(controller, toolCall.raw);
9011
+ reportUnfinishedToolCallAtFinish(controller, toolCall.raw, {
9012
+ toolName: toolCall.outerNameAttr
9013
+ });
8506
9014
  }
8507
9015
  toolCall = null;
8508
9016
  }
@@ -8520,7 +9028,8 @@ var qwen3CoderProtocol = () => ({
8520
9028
  if (!result.ok && openTag) {
8521
9029
  reportUnfinishedImplicitCallAtFinish(
8522
9030
  controller,
8523
- callState.raw || openTag + callState.buffer
9031
+ callState.raw || openTag + callState.buffer,
9032
+ callState
8524
9033
  );
8525
9034
  }
8526
9035
  } else {
@@ -8898,26 +9407,28 @@ function findToolCalls2(text, toolNames) {
8898
9407
  );
8899
9408
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
8900
9409
  }
8901
- function parseYamlContent(yamlContent, options) {
8902
- var _a, _b;
9410
+ function yamlFailureCause(failure) {
9411
+ if (failure.kind === "yaml-parse-error") {
9412
+ return { kind: "yaml-parse-error", errors: failure.errors };
9413
+ }
9414
+ return { kind: "yaml-non-mapping" };
9415
+ }
9416
+ function parseYamlContent(yamlContent) {
8903
9417
  const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
8904
9418
  if (nonEmptyLines.length === 0) {
8905
- return {};
9419
+ return { ok: true, value: {} };
8906
9420
  }
8907
9421
  const parsed = parseYamlDocumentAsMapping(normalized);
8908
9422
  if (parsed.errors.length > 0) {
8909
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
8910
- errors: parsed.errors
8911
- });
8912
- return null;
9423
+ return {
9424
+ ok: false,
9425
+ failure: { kind: "yaml-parse-error", errors: parsed.errors }
9426
+ };
8913
9427
  }
8914
9428
  if (parsed.value === null) {
8915
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
8916
- got: "non-mapping"
8917
- });
8918
- return null;
9429
+ return { ok: false, failure: { kind: "yaml-non-mapping" } };
8919
9430
  }
8920
- return parsed.value;
9431
+ return { ok: true, value: parsed.value };
8921
9432
  }
8922
9433
  function parseYamlContentForStreamProgress(yamlContent) {
8923
9434
  const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
@@ -8949,11 +9460,16 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
8949
9460
  return currentIndex;
8950
9461
  }
8951
9462
  addTextSegment(text.slice(currentIndex, tc.startIndex), processedElements);
8952
- const parsedArgs = parseYamlContent(tc.content, options);
8953
- if (parsedArgs === null) {
9463
+ const result = parseYamlContent(tc.content);
9464
+ if (!result.ok) {
8954
9465
  const originalText = text.slice(tc.startIndex, tc.endIndex);
9466
+ const cause = yamlFailureCause(result.failure);
8955
9467
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse YAML tool call", {
8956
- toolCall: originalText
9468
+ toolCall: originalText,
9469
+ toolName: tc.toolName,
9470
+ toolCallId: generateToolCallId(),
9471
+ dropReason: "malformed-tool-call-body",
9472
+ cause
8957
9473
  });
8958
9474
  processedElements.push({ type: "text", text: originalText });
8959
9475
  } else {
@@ -8961,7 +9477,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
8961
9477
  type: "tool-call",
8962
9478
  toolCallId: generateToolCallId(),
8963
9479
  toolName: tc.toolName,
8964
- input: JSON.stringify(parsedArgs)
9480
+ input: JSON.stringify(result.value)
8965
9481
  });
8966
9482
  }
8967
9483
  return tc.endIndex;
@@ -9084,9 +9600,9 @@ ${yamlContent}</${toolCall.toolName}>`;
9084
9600
  };
9085
9601
  const processToolCallEnd = (controller, toolContent, toolName, toolCallId) => {
9086
9602
  var _a;
9087
- const parsedArgs = parseYamlContent(toolContent, options);
9603
+ const result = parseYamlContent(toolContent);
9088
9604
  flushText(controller);
9089
- if (parsedArgs === null) {
9605
+ if (!result.ok) {
9090
9606
  const original = `<${toolName}>${toolContent}</${toolName}>`;
9091
9607
  const emitRawFallback = shouldEmitRawToolCallTextOnError(options);
9092
9608
  emitFailedToolInputLifecycle({
@@ -9099,12 +9615,16 @@ ${yamlContent}</${toolCall.toolName}>`;
9099
9615
  }
9100
9616
  });
9101
9617
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
9102
- toolCall: original
9618
+ toolCall: original,
9619
+ toolName,
9620
+ toolCallId,
9621
+ dropReason: "malformed-tool-call-body",
9622
+ cause: yamlFailureCause(result.failure)
9103
9623
  });
9104
9624
  } else {
9105
9625
  const finalInput = stringifyToolInputWithSchema({
9106
9626
  toolName,
9107
- args: parsedArgs,
9627
+ args: result.value,
9108
9628
  tools
9109
9629
  });
9110
9630
  if (currentToolCall && currentToolCall.toolCallId === toolCallId) {
@@ -9134,9 +9654,9 @@ ${yamlContent}</${toolCall.toolName}>`;
9134
9654
  emitToolInputProgress2(controller, buffer);
9135
9655
  const { name: toolName, toolCallId } = currentToolCall;
9136
9656
  const reconciledBuffer = stripTrailingPartialCloseTag(buffer, toolName);
9137
- const parsedArgs = parseYamlContent(reconciledBuffer, options);
9657
+ const result = parseYamlContent(reconciledBuffer);
9138
9658
  flushText(controller);
9139
- if (parsedArgs === null) {
9659
+ if (!result.ok) {
9140
9660
  const unfinishedContent = `<${toolName}>${buffer}`;
9141
9661
  const emitRawFallback = shouldEmitRawToolCallTextOnError(options);
9142
9662
  emitFailedToolInputLifecycle({
@@ -9151,12 +9671,18 @@ ${yamlContent}</${toolCall.toolName}>`;
9151
9671
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
9152
9672
  options,
9153
9673
  "Could not complete streaming YAML tool call at finish.",
9154
- { toolCall: unfinishedContent }
9674
+ {
9675
+ toolCall: unfinishedContent,
9676
+ toolCallId,
9677
+ toolName,
9678
+ dropReason: "unfinished-tool-call",
9679
+ cause: yamlFailureCause(result.failure)
9680
+ }
9155
9681
  );
9156
9682
  } else {
9157
9683
  const finalInput = stringifyToolInputWithSchema({
9158
9684
  toolName,
9159
- args: parsedArgs,
9685
+ args: result.value,
9160
9686
  tools
9161
9687
  });
9162
9688
  emitFinalizedToolInputLifecycle({