@semantictools/ai-toolbox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +778 -0
- package/package.json +38 -0
- package/src/toolmanager.mjs +605 -0
- package/src/translators/atfunc.mjs +450 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
let separator = " ----------------- \n";
|
|
4
|
+
let afterPadding = "\n";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function typifyValue( value, type ) {
|
|
8
|
+
if( type === "number" ) {
|
|
9
|
+
let n = Number( value );
|
|
10
|
+
if( !isNaN( n )) {
|
|
11
|
+
return n;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
else if( type === "boolean" ) {
|
|
15
|
+
let vLower = value.toLowerCase();
|
|
16
|
+
if( vLower === "true" || vLower === "false" ) {
|
|
17
|
+
return ( vLower === "true" );
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else if( type === "string" ) {
|
|
21
|
+
// surrounded but quotes, remove them
|
|
22
|
+
if( ( value.startsWith('"') && value.endsWith('"') ) ||
|
|
23
|
+
( value.startsWith("'") && value.endsWith("'") ) ) {
|
|
24
|
+
return value.substring( 1, value.length - 1 );
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//default to string
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
function getFunctionCallsFromText( text, interfaces, rootToolBox ) {
|
|
34
|
+
|
|
35
|
+
let lines = text.split("\n");
|
|
36
|
+
let fCalls = [];
|
|
37
|
+
|
|
38
|
+
fCalls = [];
|
|
39
|
+
for( let i=0; i<lines.length; i++ ) {
|
|
40
|
+
let line = lines[i].trim();
|
|
41
|
+
if( line.startsWith("@") ) {
|
|
42
|
+
let funcCall = ""; //line.substring(1, endIdx );
|
|
43
|
+
let paramStart = line.indexOf("(")+1;
|
|
44
|
+
let paramStartFound = paramStart != 0;
|
|
45
|
+
|
|
46
|
+
let parseState = {
|
|
47
|
+
inQuote: false,
|
|
48
|
+
escape: false,
|
|
49
|
+
buffer: ""
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let params = [];
|
|
53
|
+
for( let j=paramStart; j<line.length; j++ ) {
|
|
54
|
+
let char = line[j];
|
|
55
|
+
|
|
56
|
+
if( (char == "," || char == ")") && !parseState.escape && !parseState.inQuote ) {
|
|
57
|
+
params.push( parseState.buffer.trim() );
|
|
58
|
+
parseState.buffer = "";
|
|
59
|
+
if( char == ")" ) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if( char == "\"" && !parseState.escape ) {
|
|
64
|
+
parseState.inQuote = !parseState.inQuote;
|
|
65
|
+
parseState.buffer += char;
|
|
66
|
+
}
|
|
67
|
+
else if( char == "\\" && !parseState.escape ) {
|
|
68
|
+
parseState.escape = true;
|
|
69
|
+
}
|
|
70
|
+
else if( parseState.escape ) {
|
|
71
|
+
parseState.escape = false;
|
|
72
|
+
if( char == "n") {
|
|
73
|
+
parseState.buffer += "\n";
|
|
74
|
+
}
|
|
75
|
+
else if( char == "t") {
|
|
76
|
+
parseState.buffer += "\t";
|
|
77
|
+
}
|
|
78
|
+
else if( char == "\"") {
|
|
79
|
+
parseState.buffer += "\"";
|
|
80
|
+
}
|
|
81
|
+
else if( char == ",") {
|
|
82
|
+
parseState.buffer += ",";
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
parseState.buffer += "?";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
parseState.buffer += char;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
//adjust funcCall to not include rest if brackets and/or params exist
|
|
94
|
+
if( paramStartFound ) {
|
|
95
|
+
funcCall = line.substring(1, paramStart-1 ).trim();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if( funcCall.indexOf(".") == -1 && rootToolBox ) {
|
|
99
|
+
funcCall = rootToolBox + "." + funcCall;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//check with after the last ) there is a "with_body [[" and if so, take the rest of the line as body param,
|
|
103
|
+
// and keep adding lines untill we encounter a line that ends with "]]"
|
|
104
|
+
let bodyParam = null;
|
|
105
|
+
if( line.indexOf("with_body [[") != -1 ) {
|
|
106
|
+
bodyParam = line.substring( line.indexOf("with_body [[") + "with_body [[".length ).trim();
|
|
107
|
+
let bodyLines = [];
|
|
108
|
+
if( bodyParam.length > 0 ) {
|
|
109
|
+
bodyLines.push( bodyParam );
|
|
110
|
+
}
|
|
111
|
+
let j = i+1;
|
|
112
|
+
let bodyEndFound = false;
|
|
113
|
+
for( ; j<lines.length; j++ ) {
|
|
114
|
+
let bodyLine = lines[j];
|
|
115
|
+
if( bodyLine.indexOf("]]") != -1 ) {
|
|
116
|
+
bodyEndFound = true;
|
|
117
|
+
bodyLines.push( bodyLine.substring( 0, bodyLine.indexOf("]]") ) );
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
bodyLines.push( bodyLine );
|
|
121
|
+
}
|
|
122
|
+
if( bodyEndFound ) {
|
|
123
|
+
bodyParam = bodyLines.join("\n").trim();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fCalls.push( {
|
|
128
|
+
name: funcCall ,
|
|
129
|
+
params: params,
|
|
130
|
+
body: bodyParam
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let fCalls2 = [];
|
|
138
|
+
for( let f=0; f<fCalls.length; f++) {
|
|
139
|
+
|
|
140
|
+
let fCall = fCalls[f];
|
|
141
|
+
//find interface for fCall.name
|
|
142
|
+
//console.log("Looking for interface for function call: ", JSON.stringify( fCall,null,2 ) );
|
|
143
|
+
|
|
144
|
+
let matchingInterface = null;
|
|
145
|
+
for( let i=0; i<interfaces.length; i++ ) {
|
|
146
|
+
let thisInterface = interfaces[i];
|
|
147
|
+
//let fullName = thisInterface.domain + "." + thisInterface.name;
|
|
148
|
+
if( (thisInterface.domain + "." + thisInterface.name) == fCall.name ) {
|
|
149
|
+
matchingInterface = thisInterface;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if( matchingInterface ) {
|
|
155
|
+
|
|
156
|
+
let params2 = null;
|
|
157
|
+
if( fCall.params && fCall.params.length > 0 ) {
|
|
158
|
+
params2 = {};
|
|
159
|
+
//Params have to match order, but how.
|
|
160
|
+
//Answer, all params in interface in same array, but with type info
|
|
161
|
+
|
|
162
|
+
let iPathParams = matchingInterface.path_params || {};
|
|
163
|
+
let iQueryParams = matchingInterface.query_params || {};
|
|
164
|
+
let iFunParams = matchingInterface.params || {};
|
|
165
|
+
let iPathParamKeys = Object.keys( iPathParams );
|
|
166
|
+
let iQueryParamKeys = Object.keys( iQueryParams );
|
|
167
|
+
let iFunParamKeys = Object.keys( iFunParams );
|
|
168
|
+
|
|
169
|
+
let allParam = [];
|
|
170
|
+
for( let p=0; p<iPathParamKeys.length; p++ ) {
|
|
171
|
+
let object = iPathParams[ iPathParamKeys[p] ];
|
|
172
|
+
allParam.push(
|
|
173
|
+
{
|
|
174
|
+
name: iPathParamKeys[p],
|
|
175
|
+
type: "path",
|
|
176
|
+
dataType: object.type
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
for( let p=0; p<iQueryParamKeys.length; p++ ) {
|
|
181
|
+
let object = iQueryParams[ iQueryParamKeys[p] ];
|
|
182
|
+
allParam.push(
|
|
183
|
+
{
|
|
184
|
+
name: iQueryParamKeys[p],
|
|
185
|
+
type: "query",
|
|
186
|
+
dataType: object.type,
|
|
187
|
+
value: null
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
for( let p=0; p<iFunParamKeys.length; p++ ) {
|
|
192
|
+
let object = iFunParams[ iFunParamKeys[p] ];
|
|
193
|
+
allParam.push(
|
|
194
|
+
{
|
|
195
|
+
name: iFunParamKeys[p],
|
|
196
|
+
type: "function",
|
|
197
|
+
dataType: object.type,
|
|
198
|
+
value: null
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for( let fci=0; fci<fCall.params.length && fci<allParam.length; fci++ ) {
|
|
204
|
+
|
|
205
|
+
let paramValue = fCall.params[fci];
|
|
206
|
+
let paramType = allParam[fci].dataType;
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
paramValue = typifyValue( paramValue, paramType );
|
|
210
|
+
allParam[fci].value = paramValue;
|
|
211
|
+
|
|
212
|
+
params2[allParam[fci].name] = allParam[fci];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if( fCall.body ) {
|
|
216
|
+
params2 = params2 || {};
|
|
217
|
+
params2["@body"] = { value: fCall.body };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
fCalls2.push( {
|
|
221
|
+
name: fCall.name,
|
|
222
|
+
params: params2,
|
|
223
|
+
interface: matchingInterface
|
|
224
|
+
//interface: foundInterface
|
|
225
|
+
} );
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.log("No matching interface found for function call: ", fCall.name );
|
|
229
|
+
|
|
230
|
+
fCalls2.push( {
|
|
231
|
+
name: fCall.name,
|
|
232
|
+
error: true,
|
|
233
|
+
detail: "not found"
|
|
234
|
+
//interface: foundInterface
|
|
235
|
+
} );
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return fCalls2;
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function generateFunctionIfText_function( skill, useSeparator = false ) {
|
|
245
|
+
let interfaceText = "";
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
interfaceText += "@" + skill.domain + "." + skill.name+"( ";
|
|
250
|
+
|
|
251
|
+
let paramsExist = false;
|
|
252
|
+
if( skill.params ) {
|
|
253
|
+
|
|
254
|
+
let p=0;
|
|
255
|
+
for (let paramName in skill.params ) {
|
|
256
|
+
let param = skill.params[ paramName ];
|
|
257
|
+
let field = paramName;
|
|
258
|
+
if( param.isRequired ) {
|
|
259
|
+
field = "*" + field;
|
|
260
|
+
}
|
|
261
|
+
if( param.type != "string" ) {
|
|
262
|
+
field += "{" + param.type + "}";
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if( p>0 ) { interfaceText += ", ";}
|
|
266
|
+
interfaceText += " <" + field + ">";
|
|
267
|
+
paramsExist = true;
|
|
268
|
+
p++;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
interfaceText += " )\n";
|
|
273
|
+
|
|
274
|
+
interfaceText += "Description: " + skill.description + "\n";
|
|
275
|
+
|
|
276
|
+
if( useSeparator ) {
|
|
277
|
+
return interfaceText + separator + afterPadding ;
|
|
278
|
+
}
|
|
279
|
+
return interfaceText + afterPadding;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
function paramToText( paramName, paramObj ) {
|
|
284
|
+
let field = paramName;
|
|
285
|
+
if( paramObj.isRequired ) {
|
|
286
|
+
field = "*" + field;
|
|
287
|
+
}
|
|
288
|
+
if( paramObj.type != "string" ) {
|
|
289
|
+
field += "{" + paramObj.type + "}";
|
|
290
|
+
}
|
|
291
|
+
if( paramObj.type == "string" && paramObj.options) {
|
|
292
|
+
field += "[" + paramObj.options.join("|") + "]";
|
|
293
|
+
}
|
|
294
|
+
return "<" + field + ">";
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function generateFunctionIfText_apiWrapper(skill, useSeparator = false ) {
|
|
298
|
+
|
|
299
|
+
let interfaceText = "";
|
|
300
|
+
|
|
301
|
+
if(skill.response_type && !skill.response_type.includes("json") && skill.type == "api-wrapper") {
|
|
302
|
+
//interfaceText += "Unsupported! - " + skill.name+"() - API function with unsupported response type '" + skill.response_type + "'.\n" + afterPadding;
|
|
303
|
+
console.log ("Unsupported api response type: " + skill.response_type);
|
|
304
|
+
return "";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
interfaceText += "@" + skill.domain + "." + skill.name + "( ";
|
|
308
|
+
let paramsExist = false;
|
|
309
|
+
|
|
310
|
+
if( skill.path_params ) {
|
|
311
|
+
|
|
312
|
+
let i = 0;
|
|
313
|
+
for (let paramName in skill.path_params ) {
|
|
314
|
+
if(i>0) { interfaceText += ","; }
|
|
315
|
+
i++;
|
|
316
|
+
|
|
317
|
+
let paramText = paramToText( paramName, skill.path_params[ paramName ] );
|
|
318
|
+
|
|
319
|
+
interfaceText += " " + paramText;
|
|
320
|
+
paramsExist = true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if( skill.query_params ) {
|
|
325
|
+
|
|
326
|
+
let i=0;
|
|
327
|
+
for (let paramName in skill.query_params ) {
|
|
328
|
+
if(i>0) { interfaceText += ","; }
|
|
329
|
+
i++;
|
|
330
|
+
|
|
331
|
+
let paramText = paramToText( paramName, skill.query_params[ paramName ] );
|
|
332
|
+
|
|
333
|
+
interfaceText += " " + paramText;
|
|
334
|
+
paramsExist = true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
interfaceText += " )";
|
|
339
|
+
|
|
340
|
+
if( skill.request_body ) {
|
|
341
|
+
|
|
342
|
+
if( skill.request_body ) {
|
|
343
|
+
interfaceText += " with_body ";
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
interfaceText += "{ ";
|
|
347
|
+
let bodyObj = skill.request_body;
|
|
348
|
+
if(skill.response_type && skill.response_type.includes("json")) {
|
|
349
|
+
let bodyKeys = Object.keys( bodyObj );
|
|
350
|
+
for( let b=0; b<bodyKeys.length; b++) {
|
|
351
|
+
let key = bodyKeys[b];
|
|
352
|
+
let field = bodyObj[key];
|
|
353
|
+
if(b>0) {
|
|
354
|
+
interfaceText += ",";
|
|
355
|
+
}
|
|
356
|
+
let mandatory = "";
|
|
357
|
+
if( field.required ) {
|
|
358
|
+
mandatory = "*";
|
|
359
|
+
}
|
|
360
|
+
interfaceText += " " + mandatory + key + ": " + field.type;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
interfaceText += " }\n";
|
|
364
|
+
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
interfaceText += "{ ?unsupported body? } \n";
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
//interfaceText += padLines2( JSON.stringify( skill.request_body, null, 2 )) + "\n";
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
interfaceText += "\n";
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
interfaceText += "Description: " + skill.description + "\n";
|
|
377
|
+
|
|
378
|
+
if( useSeparator ) {
|
|
379
|
+
return separator + interfaceText + afterPadding;
|
|
380
|
+
}
|
|
381
|
+
return interfaceText + afterPadding;
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
function generateFunctionIfText(skill, separator = false) {
|
|
387
|
+
if( skill.type == "api-wrapper") {
|
|
388
|
+
return generateFunctionIfText_apiWrapper( skill, separator );
|
|
389
|
+
}
|
|
390
|
+
else if( skill.type == "function") {
|
|
391
|
+
return generateFunctionIfText_function( skill, separator );
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
function formatFunctionCallResults( fCalls ) {
|
|
399
|
+
|
|
400
|
+
let output = "";
|
|
401
|
+
|
|
402
|
+
for( let f=0; f<fCalls.length; f++ ) {
|
|
403
|
+
|
|
404
|
+
if( fCalls[f].error ) {
|
|
405
|
+
output += `Function call: ${fCalls[f].name}( ???? ) ${fCalls[f].detail}\n`;
|
|
406
|
+
|
|
407
|
+
//fuzzy matches to propose
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let params = "";
|
|
412
|
+
if( fCalls[f].params ) {
|
|
413
|
+
let paramKeys = Object.keys( fCalls[f].params );
|
|
414
|
+
for( let p=0; p<paramKeys.length; p++ ) {
|
|
415
|
+
if(p>0) params += ", ";
|
|
416
|
+
let key = paramKeys[p];
|
|
417
|
+
let value = fCalls[f].params[key].value;
|
|
418
|
+
let dataType = fCalls[f].params[key].dataType;
|
|
419
|
+
if( dataType === "string") {
|
|
420
|
+
value = `"${value}"`;
|
|
421
|
+
}
|
|
422
|
+
//params += `${key}: ${value} `;
|
|
423
|
+
params += `${value} `;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
output += `Function call: ${fCalls[f].name}( ${ params }) \n`;
|
|
427
|
+
|
|
428
|
+
let outputExpected = false || fCalls[f].interface.returns;
|
|
429
|
+
|
|
430
|
+
if( outputExpected ) output += "Returned: \n";
|
|
431
|
+
|
|
432
|
+
let fCall = fCalls[f];
|
|
433
|
+
let result = fCall.result;
|
|
434
|
+
|
|
435
|
+
if( outputExpected ) output += result + "\n\n";
|
|
436
|
+
|
|
437
|
+
//console.log("Result of ", fCall.name, ": ", JSON.stringify( result, null, 2 ) );
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
//output = converter.formatFunctionCallResults( fCalls );
|
|
441
|
+
|
|
442
|
+
return output;
|
|
443
|
+
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
// Case sensitivity preference: atfunc is case-insensitive for AI text parsing
|
|
448
|
+
export const caseSensitive = false;
|
|
449
|
+
|
|
450
|
+
export { generateFunctionIfText, getFunctionCallsFromText, formatFunctionCallResults };
|