@ai-sdk-tool/parser 1.0.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,31 +15,21 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
33
23
  createToolMiddleware: () => createToolMiddleware,
34
- defaultTemplate: () => defaultTemplate,
35
24
  gemmaToolMiddleware: () => gemmaToolMiddleware,
36
25
  hermesToolMiddleware: () => hermesToolMiddleware
37
26
  });
38
27
  module.exports = __toCommonJS(index_exports);
39
28
 
40
29
  // src/tool-call-middleware.ts
41
- var import_ai = require("ai");
42
- var RJSON = __toESM(require("relaxed-json"));
30
+ var import_provider_utils = require("@ai-sdk/provider-utils");
43
31
 
44
- // src/utils.ts
32
+ // src/utils/get-potential-start-index.ts
45
33
  function getPotentialStartIndex(text, searchedText) {
46
34
  if (searchedText.length === 0) {
47
35
  return null;
@@ -59,26 +47,606 @@ function getPotentialStartIndex(text, searchedText) {
59
47
  return null;
60
48
  }
61
49
 
50
+ // src/utils/relaxed-json.ts
51
+ function some(array, f) {
52
+ let acc = false;
53
+ for (let i = 0; i < array.length; i++) {
54
+ const result = f(array[i], i, array);
55
+ acc = result === void 0 ? false : result;
56
+ if (acc) {
57
+ return acc;
58
+ }
59
+ }
60
+ return acc;
61
+ }
62
+ function makeLexer(tokenSpecs) {
63
+ return function(contents) {
64
+ const tokens = [];
65
+ let line = 1;
66
+ function findToken() {
67
+ const result = some(tokenSpecs, (tokenSpec) => {
68
+ const m = tokenSpec.re.exec(contents);
69
+ if (m) {
70
+ const raw = m[0];
71
+ contents = contents.slice(raw.length);
72
+ return {
73
+ raw,
74
+ matched: tokenSpec.f(m)
75
+ // Process the match using the spec's function
76
+ };
77
+ } else {
78
+ return void 0;
79
+ }
80
+ });
81
+ return result === false ? void 0 : result;
82
+ }
83
+ while (contents !== "") {
84
+ const matched = findToken();
85
+ if (!matched) {
86
+ const err = new SyntaxError(
87
+ `Unexpected character: ${contents[0]}; input: ${contents.substr(
88
+ 0,
89
+ 100
90
+ )}`
91
+ );
92
+ err.line = line;
93
+ throw err;
94
+ }
95
+ const tokenWithLine = matched.matched;
96
+ tokenWithLine.line = line;
97
+ line += matched.raw.replace(/[^\n]/g, "").length;
98
+ tokens.push(tokenWithLine);
99
+ }
100
+ return tokens;
101
+ };
102
+ }
103
+ function fStringSingle(m) {
104
+ const content = m[1].replace(
105
+ /([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g,
106
+ (mm) => {
107
+ if (mm === '"') {
108
+ return '\\"';
109
+ } else if (mm === "\\'") {
110
+ return "'";
111
+ } else {
112
+ return mm;
113
+ }
114
+ }
115
+ );
116
+ const match = `"${content}"`;
117
+ return {
118
+ type: "string",
119
+ match,
120
+ // The transformed, double-quoted string representation
121
+ // Use JSON.parse on the transformed string to handle escape sequences correctly
122
+ value: JSON.parse(match)
123
+ };
124
+ }
125
+ function fStringDouble(m) {
126
+ return {
127
+ type: "string",
128
+ match: m[0],
129
+ // The raw matched string (including quotes)
130
+ value: JSON.parse(m[0])
131
+ // Use JSON.parse to handle escapes and get the value
132
+ };
133
+ }
134
+ function fIdentifier(m) {
135
+ const value = m[0];
136
+ const match = '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + // Escape backslashes and quotes
137
+ '"';
138
+ return {
139
+ type: "string",
140
+ // Treat identifiers as strings
141
+ value,
142
+ // The original identifier name
143
+ match
144
+ // The double-quoted string representation
145
+ };
146
+ }
147
+ function fComment(m) {
148
+ const match = m[0].replace(/./g, (c) => /\s/.test(c) ? c : " ");
149
+ return {
150
+ type: " ",
151
+ // Represent comments as whitespace tokens
152
+ match,
153
+ // String containing original newlines and spaces for other chars
154
+ value: void 0
155
+ // Comments don't have a semantic value
156
+ };
157
+ }
158
+ function fNumber(m) {
159
+ return {
160
+ type: "number",
161
+ match: m[0],
162
+ // The raw matched number string
163
+ value: parseFloat(m[0])
164
+ // Convert string to number
165
+ };
166
+ }
167
+ function fKeyword(m) {
168
+ let value;
169
+ switch (m[0]) {
170
+ case "null":
171
+ value = null;
172
+ break;
173
+ case "true":
174
+ value = true;
175
+ break;
176
+ case "false":
177
+ value = false;
178
+ break;
179
+ default:
180
+ throw new Error(`Unexpected keyword: ${m[0]}`);
181
+ }
182
+ return {
183
+ type: "atom",
184
+ // Use 'atom' type for these literals
185
+ match: m[0],
186
+ // The raw matched keyword
187
+ value
188
+ // The corresponding JavaScript value
189
+ };
190
+ }
191
+ function makeTokenSpecs(relaxed) {
192
+ function f(type) {
193
+ return function(m) {
194
+ return { type, match: m[0], value: void 0 };
195
+ };
196
+ }
197
+ let tokenSpecs = [
198
+ { re: /^\s+/, f: f(" ") },
199
+ // Whitespace
200
+ { re: /^\{/, f: f("{") },
201
+ // Object start
202
+ { re: /^\}/, f: f("}") },
203
+ // Object end
204
+ { re: /^\[/, f: f("[") },
205
+ // Array start
206
+ { re: /^\]/, f: f("]") },
207
+ // Array end
208
+ { re: /^,/, f: f(",") },
209
+ // Comma separator
210
+ { re: /^:/, f: f(":") },
211
+ // Key-value separator
212
+ { re: /^(?:true|false|null)/, f: fKeyword },
213
+ // Keywords
214
+ // Number: optional sign, digits, optional decimal part, optional exponent
215
+ { re: /^\-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/, f: fNumber },
216
+ // String: double-quoted, handles escapes
217
+ { re: /^"(?:[^"\\]|\\["bnrtf\\\/]|\\u[0-9a-fA-F]{4})*"/, f: fStringDouble }
218
+ ];
219
+ if (relaxed) {
220
+ tokenSpecs = tokenSpecs.concat([
221
+ // Single-quoted strings
222
+ {
223
+ re: /^'((?:[^'\\]|\\['bnrtf\\\/]|\\u[0-9a-fA-F]{4})*)'/,
224
+ f: fStringSingle
225
+ },
226
+ // Single-line comments (// ...)
227
+ { re: /^\/\/.*?(?:\r\n|\r|\n)/, f: fComment },
228
+ // Multi-line comments (/* ... */)
229
+ { re: /^\/\*[\s\S]*?\*\//, f: fComment },
230
+ // Unquoted identifiers (treated as strings)
231
+ // Allows letters, numbers, _, -, +, ., *, ?, !, |, &, %, ^, /, #, \
232
+ { re: /^[$a-zA-Z0-9_\-+\.\*\?!\|&%\^\/#\\]+/, f: fIdentifier }
233
+ // Note: The order matters here. Identifiers are checked after keywords/numbers.
234
+ ]);
235
+ }
236
+ return tokenSpecs;
237
+ }
238
+ var lexer = makeLexer(makeTokenSpecs(true));
239
+ var strictLexer = makeLexer(makeTokenSpecs(false));
240
+ function previousNWSToken(tokens, index) {
241
+ for (; index >= 0; index--) {
242
+ if (tokens[index].type !== " ") {
243
+ return index;
244
+ }
245
+ }
246
+ return void 0;
247
+ }
248
+ function stripTrailingComma(tokens) {
249
+ const res = [];
250
+ tokens.forEach((token, index) => {
251
+ if (index > 0 && (token.type === "]" || token.type === "}")) {
252
+ const prevNWSTokenIndex = previousNWSToken(res, res.length - 1);
253
+ if (prevNWSTokenIndex !== void 0 && res[prevNWSTokenIndex].type === ",") {
254
+ const preCommaIndex = previousNWSToken(res, prevNWSTokenIndex - 1);
255
+ if (preCommaIndex !== void 0 && res[preCommaIndex].type !== "[" && res[preCommaIndex].type !== "{") {
256
+ res[prevNWSTokenIndex] = {
257
+ type: " ",
258
+ match: " ",
259
+ // Represent as a single space
260
+ value: void 0,
261
+ // Whitespace has no value
262
+ line: res[prevNWSTokenIndex].line
263
+ // Preserve original line number
264
+ };
265
+ }
266
+ }
267
+ }
268
+ res.push(token);
269
+ });
270
+ return res;
271
+ }
272
+ function popToken(tokens, state) {
273
+ const token = tokens[state.pos];
274
+ state.pos += 1;
275
+ if (!token) {
276
+ const lastLine = tokens.length !== 0 ? tokens[tokens.length - 1].line : 1;
277
+ return { type: "eof", match: "", value: void 0, line: lastLine };
278
+ }
279
+ return token;
280
+ }
281
+ function strToken(token) {
282
+ switch (token.type) {
283
+ case "atom":
284
+ case "string":
285
+ case "number":
286
+ return `${token.type} ${token.match}`;
287
+ case "eof":
288
+ return "end-of-file";
289
+ default:
290
+ return `'${token.type}'`;
291
+ }
292
+ }
293
+ function skipColon(tokens, state) {
294
+ const colon = popToken(tokens, state);
295
+ if (colon.type !== ":") {
296
+ const message = `Unexpected token: ${strToken(colon)}, expected ':'`;
297
+ if (state.tolerant) {
298
+ state.warnings.push({
299
+ message,
300
+ line: colon.line
301
+ });
302
+ state.pos -= 1;
303
+ } else {
304
+ const err = new SyntaxError(message);
305
+ err.line = colon.line;
306
+ throw err;
307
+ }
308
+ }
309
+ }
310
+ function skipPunctuation(tokens, state, valid) {
311
+ const punctuation = [",", ":", "]", "}"];
312
+ let token = popToken(tokens, state);
313
+ while (true) {
314
+ if (valid && valid.includes(token.type)) {
315
+ return token;
316
+ } else if (token.type === "eof") {
317
+ return token;
318
+ } else if (punctuation.includes(token.type)) {
319
+ const message = `Unexpected token: ${strToken(
320
+ token
321
+ )}, expected '[', '{', number, string or atom`;
322
+ if (state.tolerant) {
323
+ state.warnings.push({
324
+ message,
325
+ line: token.line
326
+ });
327
+ token = popToken(tokens, state);
328
+ } else {
329
+ const err = new SyntaxError(message);
330
+ err.line = token.line;
331
+ throw err;
332
+ }
333
+ } else {
334
+ return token;
335
+ }
336
+ }
337
+ }
338
+ function raiseError(state, token, message) {
339
+ if (state.tolerant) {
340
+ state.warnings.push({
341
+ message,
342
+ line: token.line
343
+ });
344
+ } else {
345
+ const err = new SyntaxError(message);
346
+ err.line = token.line;
347
+ throw err;
348
+ }
349
+ }
350
+ function raiseUnexpected(state, token, expected) {
351
+ raiseError(
352
+ state,
353
+ token,
354
+ `Unexpected token: ${strToken(token)}, expected ${expected}`
355
+ );
356
+ }
357
+ function checkDuplicates(state, obj, token) {
358
+ const key = String(token.value);
359
+ if (!state.duplicate && Object.prototype.hasOwnProperty.call(obj, key)) {
360
+ raiseError(state, token, `Duplicate key: ${key}`);
361
+ }
362
+ }
363
+ function appendPair(state, obj, key, value) {
364
+ const finalValue = state.reviver ? state.reviver(key, value) : value;
365
+ if (finalValue !== void 0) {
366
+ obj[key] = finalValue;
367
+ }
368
+ }
369
+ function parsePair(tokens, state, obj) {
370
+ let token = skipPunctuation(tokens, state, [":", "string", "number", "atom"]);
371
+ let key;
372
+ let value;
373
+ if (token.type !== "string") {
374
+ raiseUnexpected(state, token, "string key");
375
+ if (state.tolerant) {
376
+ switch (token.type) {
377
+ case ":":
378
+ token = {
379
+ type: "string",
380
+ value: "null",
381
+ match: '"null"',
382
+ line: token.line
383
+ };
384
+ state.pos -= 1;
385
+ break;
386
+ case "number":
387
+ // Use number as string key
388
+ case "atom":
389
+ token = {
390
+ type: "string",
391
+ value: String(token.value),
392
+ match: `"${token.value}"`,
393
+ line: token.line
394
+ };
395
+ break;
396
+ case "[":
397
+ // Assume missing key before an array
398
+ case "{":
399
+ state.pos -= 1;
400
+ value = parseAny(tokens, state);
401
+ checkDuplicates(state, obj, {
402
+ type: "string",
403
+ value: "null",
404
+ match: '"null"',
405
+ line: token.line
406
+ });
407
+ appendPair(state, obj, "null", value);
408
+ return;
409
+ // Finished parsing this "pair"
410
+ case "eof":
411
+ return;
412
+ // Cannot recover
413
+ default:
414
+ return;
415
+ }
416
+ } else {
417
+ return;
418
+ }
419
+ }
420
+ checkDuplicates(state, obj, token);
421
+ key = String(token.value);
422
+ skipColon(tokens, state);
423
+ value = parseAny(tokens, state);
424
+ appendPair(state, obj, key, value);
425
+ }
426
+ function parseElement(tokens, state, arr) {
427
+ const key = arr.length;
428
+ const value = parseAny(tokens, state);
429
+ arr[key] = state.reviver ? state.reviver(String(key), value) : value;
430
+ }
431
+ function parseObject(tokens, state) {
432
+ const obj = {};
433
+ return parseMany(tokens, state, obj, {
434
+ skip: [":", "}"],
435
+ // Initially skip over colon or closing brace (for empty/tolerant cases)
436
+ elementParser: parsePair,
437
+ // Use parsePair to parse each key-value element
438
+ elementName: "string key",
439
+ // Expected element type for errors
440
+ endSymbol: "}"
441
+ // The closing token for an object
442
+ });
443
+ }
444
+ function parseArray(tokens, state) {
445
+ const arr = [];
446
+ return parseMany(tokens, state, arr, {
447
+ skip: ["]"],
448
+ // Initially skip over closing bracket (for empty/tolerant cases)
449
+ elementParser: parseElement,
450
+ // Use parseElement to parse each array item
451
+ elementName: "json value",
452
+ // Expected element type for errors
453
+ endSymbol: "]"
454
+ // The closing token for an array
455
+ });
456
+ }
457
+ function parseMany(tokens, state, result, opts) {
458
+ let token = skipPunctuation(tokens, state, opts.skip);
459
+ if (token.type === "eof") {
460
+ raiseUnexpected(state, token, `'${opts.endSymbol}' or ${opts.elementName}`);
461
+ if (state.tolerant) {
462
+ return result;
463
+ } else {
464
+ return result;
465
+ }
466
+ }
467
+ if (token.type === opts.endSymbol) {
468
+ return result;
469
+ }
470
+ state.pos -= 1;
471
+ opts.elementParser(tokens, state, result);
472
+ while (true) {
473
+ token = popToken(tokens, state);
474
+ if (token.type !== opts.endSymbol && token.type !== ",") {
475
+ raiseUnexpected(state, token, `',' or '${opts.endSymbol}'`);
476
+ if (state.tolerant) {
477
+ if (token.type === "eof") {
478
+ return result;
479
+ }
480
+ state.pos -= 1;
481
+ } else {
482
+ return result;
483
+ }
484
+ }
485
+ switch (token.type) {
486
+ case opts.endSymbol:
487
+ return result;
488
+ case ",":
489
+ const nextToken = tokens[state.pos];
490
+ if (state.tolerant && nextToken && nextToken.type === opts.endSymbol) {
491
+ raiseError(state, token, `Trailing comma before '${opts.endSymbol}'`);
492
+ popToken(tokens, state);
493
+ return result;
494
+ }
495
+ opts.elementParser(tokens, state, result);
496
+ break;
497
+ // Default case is only reachable in tolerant mode recovery above
498
+ default:
499
+ opts.elementParser(tokens, state, result);
500
+ break;
501
+ }
502
+ }
503
+ }
504
+ function endChecks(tokens, state, ret) {
505
+ if (state.pos < tokens.length) {
506
+ if (state.tolerant) {
507
+ skipPunctuation(tokens, state);
508
+ }
509
+ if (state.pos < tokens.length) {
510
+ raiseError(
511
+ state,
512
+ tokens[state.pos],
513
+ `Unexpected token: ${strToken(tokens[state.pos])}, expected end-of-input`
514
+ );
515
+ }
516
+ }
517
+ if (state.tolerant && state.warnings.length > 0) {
518
+ const message = state.warnings.length === 1 ? state.warnings[0].message : `${state.warnings.length} parse warnings`;
519
+ const err = new SyntaxError(message);
520
+ err.line = state.warnings[0].line;
521
+ err.warnings = state.warnings;
522
+ err.obj = ret;
523
+ throw err;
524
+ }
525
+ }
526
+ function parseAny(tokens, state, end = false) {
527
+ const token = skipPunctuation(tokens, state);
528
+ let ret;
529
+ if (token.type === "eof") {
530
+ if (end) {
531
+ raiseUnexpected(state, token, "json value");
532
+ }
533
+ raiseUnexpected(state, token, "json value");
534
+ return void 0;
535
+ }
536
+ switch (token.type) {
537
+ case "{":
538
+ ret = parseObject(tokens, state);
539
+ break;
540
+ case "[":
541
+ ret = parseArray(tokens, state);
542
+ break;
543
+ case "string":
544
+ // String literal
545
+ case "number":
546
+ // Number literal
547
+ case "atom":
548
+ ret = token.value;
549
+ break;
550
+ default:
551
+ raiseUnexpected(state, token, "json value");
552
+ if (state.tolerant) {
553
+ ret = null;
554
+ } else {
555
+ return void 0;
556
+ }
557
+ }
558
+ if (end) {
559
+ ret = state.reviver ? state.reviver("", ret) : ret;
560
+ endChecks(tokens, state, ret);
561
+ }
562
+ return ret;
563
+ }
564
+ function parse(text, optsOrReviver) {
565
+ let options = {};
566
+ if (typeof optsOrReviver === "function") {
567
+ options.reviver = optsOrReviver;
568
+ } else if (optsOrReviver !== null && typeof optsOrReviver === "object") {
569
+ options = { ...optsOrReviver };
570
+ } else if (optsOrReviver !== void 0) {
571
+ throw new TypeError(
572
+ "Second argument must be a reviver function or an options object."
573
+ );
574
+ }
575
+ if (options.relaxed === void 0) {
576
+ if (options.warnings === true || options.tolerant === true) {
577
+ options.relaxed = true;
578
+ } else if (options.warnings === false && options.tolerant === false) {
579
+ options.relaxed = false;
580
+ } else {
581
+ options.relaxed = true;
582
+ }
583
+ }
584
+ options.tolerant = options.tolerant || options.warnings || false;
585
+ options.warnings = options.warnings || false;
586
+ options.duplicate = options.duplicate || false;
587
+ if (!options.relaxed && !options.warnings && !options.tolerant) {
588
+ if (!options.duplicate) {
589
+ } else {
590
+ return JSON.parse(text, options.reviver);
591
+ }
592
+ }
593
+ const lexerToUse = options.relaxed ? lexer : strictLexer;
594
+ let tokens = lexerToUse(text);
595
+ if (options.relaxed) {
596
+ tokens = stripTrailingComma(tokens);
597
+ }
598
+ if (options.warnings || options.tolerant) {
599
+ tokens = tokens.filter((token) => token.type !== " ");
600
+ const state = {
601
+ pos: 0,
602
+ reviver: options.reviver,
603
+ tolerant: options.tolerant,
604
+ duplicate: !options.duplicate,
605
+ // Internal state: true means *check* for duplicates
606
+ warnings: []
607
+ };
608
+ return parseAny(tokens, state, true);
609
+ } else {
610
+ const newtext = tokens.reduce((str, token) => {
611
+ return str + token.match;
612
+ }, "");
613
+ if (!options.relaxed && !options.warnings && !options.tolerant && options.duplicate) {
614
+ return JSON.parse(text, options.reviver);
615
+ } else if (options.warnings || options.tolerant || !options.duplicate) {
616
+ tokens = lexerToUse(text);
617
+ if (options.relaxed) {
618
+ tokens = stripTrailingComma(tokens);
619
+ }
620
+ tokens = tokens.filter((token) => token.type !== " ");
621
+ const state = {
622
+ pos: 0,
623
+ reviver: options.reviver,
624
+ tolerant: options.tolerant || false,
625
+ // Ensure boolean
626
+ duplicate: !options.duplicate,
627
+ // true = check duplicates
628
+ warnings: []
629
+ };
630
+ return parseAny(tokens, state, true);
631
+ } else {
632
+ tokens = lexer(text);
633
+ tokens = stripTrailingComma(tokens);
634
+ const newtext2 = tokens.reduce((str, token) => str + token.match, "");
635
+ return JSON.parse(newtext2, options.reviver);
636
+ }
637
+ }
638
+ }
639
+
62
640
  // src/tool-call-middleware.ts
63
- var defaultTemplate = (tools) => `You are a function calling AI model.
64
- You are provided with function signatures within <tools></tools> XML tags.
65
- You may call one or more functions to assist with the user query.
66
- Don't make assumptions about what values to plug into functions.
67
- Here are the available tools: <tools>${tools}</tools>
68
- Use the following pydantic model json schema for each tool call you will make: {'title': 'FunctionCall', 'type': 'object', 'properties': {'arguments': {'title': 'Arguments', 'type': 'object'}, 'name': {'title': 'Name', 'type': 'string'}}, 'required': ['arguments', 'name']}
69
- For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
70
- <tool_call>
71
- {'arguments': <args-dict>, 'name': <function-name>}
72
- </tool_call>`;
73
641
  function createToolMiddleware({
74
- toolCallTag = "<tool_call>",
75
- toolCallEndTag = "</tool_call>",
76
- toolResponseTag = "<tool_response>",
77
- toolResponseEndTag = "</tool_response>",
78
- toolSystemPromptTemplate = defaultTemplate
642
+ toolCallTag,
643
+ toolCallEndTag,
644
+ toolResponseTag,
645
+ toolResponseEndTag,
646
+ toolSystemPromptTemplate
79
647
  }) {
80
648
  return {
81
- middlewareVersion: "v1",
649
+ middlewareVersion: "v2",
82
650
  wrapStream: async ({ doStream }) => {
83
651
  const { stream, ...rest } = await doStream();
84
652
  let isFirstToolCall = true;
@@ -94,30 +662,30 @@ function createToolMiddleware({
94
662
  if (toolCallBuffer.length > 0) {
95
663
  toolCallBuffer.forEach((toolCall) => {
96
664
  try {
97
- const parsedToolCall = RJSON.parse(toolCall);
665
+ const parsedToolCall = parse(toolCall);
98
666
  controller.enqueue({
99
667
  type: "tool-call",
100
668
  toolCallType: "function",
101
- toolCallId: (0, import_ai.generateId)(),
669
+ toolCallId: (0, import_provider_utils.generateId)(),
102
670
  toolName: parsedToolCall.name,
103
671
  args: JSON.stringify(parsedToolCall.arguments)
104
672
  });
105
673
  } catch (e) {
106
674
  console.error(`Error parsing tool call: ${toolCall}`, e);
107
675
  controller.enqueue({
108
- type: "text-delta",
109
- textDelta: `Failed to parse tool call: ${e}`
676
+ type: "text",
677
+ text: `Failed to parse tool call: ${e}`
110
678
  });
111
679
  }
112
680
  });
113
681
  }
114
682
  controller.enqueue(chunk);
115
683
  return;
116
- } else if (chunk.type !== "text-delta") {
684
+ } else if (chunk.type !== "text") {
117
685
  controller.enqueue(chunk);
118
686
  return;
119
687
  }
120
- buffer += chunk.textDelta;
688
+ buffer += chunk.text;
121
689
  function publish(text) {
122
690
  if (text.length > 0) {
123
691
  const prefix = afterSwitch && (isToolCall ? !isFirstToolCall : !isFirstText) ? "\n" : "";
@@ -128,8 +696,8 @@ function createToolMiddleware({
128
696
  toolCallBuffer[toolCallIndex] += text;
129
697
  } else {
130
698
  controller.enqueue({
131
- type: "text-delta",
132
- textDelta: prefix + text
699
+ type: "text",
700
+ text: prefix + text
133
701
  });
134
702
  }
135
703
  afterSwitch = false;
@@ -168,32 +736,86 @@ function createToolMiddleware({
168
736
  };
169
737
  },
170
738
  wrapGenerate: async ({ doGenerate }) => {
171
- var _a;
172
739
  const result = await doGenerate();
173
- if (!((_a = result.text) == null ? void 0 : _a.includes(toolCallTag))) {
740
+ if (result.content.length === 0) {
174
741
  return result;
175
742
  }
176
743
  const toolCallRegex = new RegExp(
177
744
  `${toolCallTag}(.*?)(?:${toolCallEndTag}|$)`,
178
745
  "gs"
179
746
  );
180
- const matches = [...result.text.matchAll(toolCallRegex)];
181
- const function_call_tuples = matches.map((match) => match[1] || match[2]);
747
+ const newContent = result.content.flatMap(
748
+ (contentItem) => {
749
+ if (contentItem.type !== "text" || !contentItem.text.includes(toolCallTag)) {
750
+ return [contentItem];
751
+ }
752
+ const text = contentItem.text;
753
+ const processedElements = [];
754
+ let currentIndex = 0;
755
+ let match;
756
+ const parseAndCreateToolCall = (toolCallJson) => {
757
+ try {
758
+ const parsedToolCall = parse(toolCallJson);
759
+ if (!parsedToolCall || typeof parsedToolCall.name !== "string" || typeof parsedToolCall.arguments === "undefined") {
760
+ console.error(
761
+ "Failed to parse tool call: Invalid structure",
762
+ toolCallJson
763
+ );
764
+ return null;
765
+ }
766
+ return {
767
+ type: "tool-call",
768
+ toolCallType: "function",
769
+ toolCallId: (0, import_provider_utils.generateId)(),
770
+ toolName: parsedToolCall.name,
771
+ // Ensure args is always a JSON string
772
+ args: typeof parsedToolCall.arguments === "string" ? parsedToolCall.arguments : JSON.stringify(parsedToolCall.arguments)
773
+ };
774
+ } catch (error) {
775
+ console.error(
776
+ "Failed to parse tool call JSON:",
777
+ error,
778
+ "JSON:",
779
+ toolCallJson
780
+ );
781
+ return null;
782
+ }
783
+ };
784
+ while ((match = toolCallRegex.exec(text)) !== null) {
785
+ const startIndex = match.index;
786
+ const endIndex = startIndex + match[0].length;
787
+ const toolCallJson = match[1];
788
+ if (startIndex > currentIndex) {
789
+ const textSegment = text.substring(currentIndex, startIndex);
790
+ if (textSegment.trim()) {
791
+ processedElements.push({ type: "text", text: textSegment });
792
+ }
793
+ }
794
+ if (toolCallJson) {
795
+ const toolCallObject = parseAndCreateToolCall(toolCallJson);
796
+ if (toolCallObject) {
797
+ processedElements.push(toolCallObject);
798
+ } else {
799
+ console.warn(
800
+ `Could not process tool call, keeping original text: ${match[0]}`
801
+ );
802
+ processedElements.push({ type: "text", text: match[0] });
803
+ }
804
+ }
805
+ currentIndex = endIndex;
806
+ }
807
+ if (currentIndex < text.length) {
808
+ const remainingText = text.substring(currentIndex);
809
+ if (remainingText.trim()) {
810
+ processedElements.push({ type: "text", text: remainingText });
811
+ }
812
+ }
813
+ return processedElements;
814
+ }
815
+ );
182
816
  return {
183
817
  ...result,
184
- // TODO: Return the remaining value after extracting the tool call tag.
185
- text: "",
186
- toolCalls: function_call_tuples.map((toolCall) => {
187
- const parsedToolCall = RJSON.parse(toolCall);
188
- const toolName = parsedToolCall.name;
189
- const args = parsedToolCall.arguments;
190
- return {
191
- toolCallType: "function",
192
- toolCallId: (0, import_ai.generateId)(),
193
- toolName,
194
- args: RJSON.stringify(args)
195
- };
196
- })
818
+ content: newContent
197
819
  };
198
820
  },
199
821
  transformParams: async ({ params }) => {
@@ -232,9 +854,8 @@ function createToolMiddleware({
232
854
  }
233
855
  return message;
234
856
  });
235
- const originalToolDefinitions = params.mode.type === "regular" && params.mode.tools ? params.mode.tools : {};
236
857
  const HermesPrompt = toolSystemPromptTemplate(
237
- JSON.stringify(Object.entries(originalToolDefinitions))
858
+ JSON.stringify(Object.entries(params.tools || {}))
238
859
  );
239
860
  const toolSystemPrompt = processedPrompt[0].role === "system" ? [
240
861
  {
@@ -251,11 +872,10 @@ function createToolMiddleware({
251
872
  ];
252
873
  return {
253
874
  ...params,
254
- mode: {
255
- // set the mode back to regular and remove the default tools.
256
- type: "regular"
257
- },
258
- prompt: toolSystemPrompt
875
+ prompt: toolSystemPrompt,
876
+ // set the mode back to regular and remove the default tools.
877
+ tools: [],
878
+ toolChoice: void 0
259
879
  };
260
880
  }
261
881
  };
@@ -265,23 +885,39 @@ function createToolMiddleware({
265
885
  var gemmaToolMiddleware = createToolMiddleware({
266
886
  toolSystemPromptTemplate(tools) {
267
887
  return `You have access to functions. If you decide to invoke any of the function(s),
268
- you MUST put it in the format of
269
- \`\`\`tool_call
270
- {'name': <function-name>, 'arguments': <args-dict>}
271
- \`\`\`
272
- You SHOULD NOT include any other text in the response if you call a function
273
- ${tools}`;
888
+ you MUST put it in the format of
889
+ \`\`\`tool_call
890
+ {'name': <function-name>, 'arguments': <args-dict>}
891
+ \`\`\`
892
+ You SHOULD NOT include any other text in the response if you call a function
893
+ ${tools}`;
274
894
  },
275
895
  toolCallTag: "```tool_call\n",
276
896
  toolCallEndTag: "```",
277
897
  toolResponseTag: "```tool_response\n",
278
898
  toolResponseEndTag: "\n```"
279
899
  });
280
- var hermesToolMiddleware = createToolMiddleware({});
900
+ var hermesToolMiddleware = createToolMiddleware({
901
+ toolSystemPromptTemplate(tools) {
902
+ return `You are a function calling AI model.
903
+ You are provided with function signatures within <tools></tools> XML tags.
904
+ You may call one or more functions to assist with the user query.
905
+ Don't make assumptions about what values to plug into functions.
906
+ Here are the available tools: <tools>${tools}</tools>
907
+ Use the following pydantic model json schema for each tool call you will make: {'title': 'FunctionCall', 'type': 'object', 'properties': {'arguments': {'title': 'Arguments', 'type': 'object'}, 'name': {'title': 'Name', 'type': 'string'}}, 'required': ['arguments', 'name']}
908
+ For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
909
+ <tool_call>
910
+ {'arguments': <args-dict>, 'name': <function-name>}
911
+ </tool_call>`;
912
+ },
913
+ toolCallTag: "<tool_call>",
914
+ toolCallEndTag: "</tool_call>",
915
+ toolResponseTag: "<tool_response>",
916
+ toolResponseEndTag: "</tool_response>"
917
+ });
281
918
  // Annotate the CommonJS export names for ESM import in node:
282
919
  0 && (module.exports = {
283
920
  createToolMiddleware,
284
- defaultTemplate,
285
921
  gemmaToolMiddleware,
286
922
  hermesToolMiddleware
287
923
  });