@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.d.mts +11 -12
- package/dist/index.d.ts +11 -12
- package/dist/index.js +706 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +705 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
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
|
|
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
|
|
75
|
-
toolCallEndTag
|
|
76
|
-
toolResponseTag
|
|
77
|
-
toolResponseEndTag
|
|
78
|
-
toolSystemPromptTemplate
|
|
642
|
+
toolCallTag,
|
|
643
|
+
toolCallEndTag,
|
|
644
|
+
toolResponseTag,
|
|
645
|
+
toolResponseEndTag,
|
|
646
|
+
toolSystemPromptTemplate
|
|
79
647
|
}) {
|
|
80
648
|
return {
|
|
81
|
-
middlewareVersion: "
|
|
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 =
|
|
665
|
+
const parsedToolCall = parse(toolCall);
|
|
98
666
|
controller.enqueue({
|
|
99
667
|
type: "tool-call",
|
|
100
668
|
toolCallType: "function",
|
|
101
|
-
toolCallId: (0,
|
|
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
|
|
109
|
-
|
|
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
|
|
684
|
+
} else if (chunk.type !== "text") {
|
|
117
685
|
controller.enqueue(chunk);
|
|
118
686
|
return;
|
|
119
687
|
}
|
|
120
|
-
buffer += chunk.
|
|
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
|
|
132
|
-
|
|
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 (
|
|
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
|
|
181
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
});
|