@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.
@@ -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 };