aimyapi 1.0.8 → 1.0.10
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 +21 -21
- package/README.md +221 -195
- package/dist/index.cjs +233 -110
- package/dist/index.d.cts +16 -8
- package/dist/index.d.mts +16 -8
- package/dist/index.d.ts +16 -8
- package/dist/index.js +233 -110
- package/dist/index.mjs +235 -112
- package/example/example1.ts +41 -30
- package/example/example2.ts +58 -58
- package/example/example3.ts +69 -69
- package/example/ordering_api.md +94 -94
- package/example/ordering_api.ts +191 -191
- package/example/ordering_api_impl.ts +207 -207
- package/example/sales_api.md +1 -5
- package/example/sales_api.ts +31 -29
- package/example/sales_api_impl.ts +74 -60
- package/package.json +2 -3
- package/prompts/generate-code-prompt.md +37 -0
- package/src/index.ts +79 -55
- package/src/log-tester-inject.ts +233 -0
- package/src/log-tester.ts +185 -0
- package/src/logger.ts +113 -0
- package/src/sandbox-wrappers.ts +296 -249
- package/src/sandbox.ts +35 -58
- package/src/utils.ts +33 -3
- package/tsconfig.json +12 -12
- package/prompts/create-task-prompt.md +0 -37
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire } from 'module';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { OpenAI } from 'openai';
|
|
4
|
-
import { getQuickJS } from 'quickjs-emscripten';
|
|
4
|
+
import { isSuccess, getQuickJS } from 'quickjs-emscripten';
|
|
5
5
|
import * as ts from 'typescript';
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import
|
|
6
|
+
import { ZodError, z } from 'zod';
|
|
7
|
+
import path from 'path';
|
|
8
8
|
|
|
9
9
|
var require$1 = (
|
|
10
10
|
true
|
|
@@ -12,23 +12,104 @@ var require$1 = (
|
|
|
12
12
|
: require
|
|
13
13
|
);
|
|
14
14
|
|
|
15
|
+
class Logger {
|
|
16
|
+
constructor(debug = false) {
|
|
17
|
+
this.logs = [];
|
|
18
|
+
this.debug = false;
|
|
19
|
+
this.debug = debug;
|
|
20
|
+
}
|
|
21
|
+
getLogs() {
|
|
22
|
+
return this.logs;
|
|
23
|
+
}
|
|
24
|
+
addEntry(type, args, source) {
|
|
25
|
+
if (Array.isArray(args)) {
|
|
26
|
+
this.logs.push({ type, args, source });
|
|
27
|
+
} else {
|
|
28
|
+
this.logs.push({ type, args: [args], source });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
log(args, source) {
|
|
32
|
+
this.addEntry("log", args, source);
|
|
33
|
+
if (this.debug) {
|
|
34
|
+
console.log(`[${source}]:`, ...args);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
trace(fnName, fnArgs, result) {
|
|
38
|
+
this.logs.push({ type: "trace", fnName, fnArgs, result });
|
|
39
|
+
if (this.debug) {
|
|
40
|
+
console.debug(`[sandbox]: ${fnName}(${fnArgs.map((arg) => JSON.stringify(Logger.limitObjectForLogs(arg))).join(",")}) -> ${JSON.stringify(Logger.limitObjectForLogs(result))}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
error(args, source) {
|
|
44
|
+
this.addEntry("error", args, source);
|
|
45
|
+
if (this.debug) {
|
|
46
|
+
console.error(`[${source}]:`, ...args);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
clear() {
|
|
50
|
+
this.logs = [];
|
|
51
|
+
}
|
|
52
|
+
getPrettyLogs() {
|
|
53
|
+
return this.logs.map((entry) => Logger.limitObjectForLogs(entry));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns a trimmed copy of `value` that is safe to log.
|
|
57
|
+
* - Objects/arrays nested deeper than `maxDepth` become "[Object]" / "[Array(n)]".
|
|
58
|
+
* - Arrays longer than `maxArrayItems` keep the first items plus a "+N more items" string.
|
|
59
|
+
* - Circular references become "[Circular]".
|
|
60
|
+
*/
|
|
61
|
+
static limitObjectForLogs(value, maxDepth = 3, maxArrayItems = 5) {
|
|
62
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
63
|
+
const trim = (val, depth) => {
|
|
64
|
+
if (val === null || typeof val !== "object") {
|
|
65
|
+
if (typeof val === "function") return `[Function${val.name ? `: ${val.name}` : ""}]`;
|
|
66
|
+
if (typeof val === "bigint") return `${val}n`;
|
|
67
|
+
if (typeof val === "symbol") return val.toString();
|
|
68
|
+
return val;
|
|
69
|
+
}
|
|
70
|
+
if (val instanceof Date) return val.toISOString();
|
|
71
|
+
if (val instanceof Error) {
|
|
72
|
+
return { name: val.name, message: val.message, stack: val.stack };
|
|
73
|
+
}
|
|
74
|
+
if (seen.has(val)) return "[Circular]";
|
|
75
|
+
if (depth >= maxDepth) {
|
|
76
|
+
return Array.isArray(val) ? `[Array(${val.length})]` : "[Object]";
|
|
77
|
+
}
|
|
78
|
+
seen.add(val);
|
|
79
|
+
let result;
|
|
80
|
+
if (Array.isArray(val)) {
|
|
81
|
+
result = val.slice(0, maxArrayItems).map((item) => trim(item, depth + 1));
|
|
82
|
+
if (val.length > maxArrayItems) {
|
|
83
|
+
result.push(`+${val.length - maxArrayItems} more items`);
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
result = {};
|
|
87
|
+
for (const key of Object.keys(val)) {
|
|
88
|
+
result[key] = trim(val[key], depth + 1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
seen.delete(val);
|
|
92
|
+
return result;
|
|
93
|
+
};
|
|
94
|
+
return trim(value, 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
15
98
|
let promiseId = 0;
|
|
16
99
|
let openPromises = {};
|
|
17
|
-
function wrapPromise(vm, promise, beginAsyncProcess, endAsyncProcess) {
|
|
100
|
+
function wrapPromise(vm, promise, beginAsyncProcess, endAsyncProcess, logger) {
|
|
18
101
|
promiseId += 1;
|
|
19
102
|
const vmPromise = vm.newPromise();
|
|
20
103
|
vmPromise._promiseId = promiseId;
|
|
21
104
|
beginAsyncProcess();
|
|
22
105
|
promise.then((...args) => {
|
|
23
106
|
endAsyncProcess();
|
|
24
|
-
const wrappedArgs = args.map((arg) => wrap(vm, arg, void 0, beginAsyncProcess, endAsyncProcess));
|
|
107
|
+
const wrappedArgs = args.map((arg) => wrap(vm, arg, void 0, beginAsyncProcess, endAsyncProcess, logger));
|
|
25
108
|
openPromises[vmPromise._promiseId] = null;
|
|
26
109
|
vmPromise.resolve(...wrappedArgs);
|
|
27
110
|
wrappedArgs.forEach((arg) => arg.dispose());
|
|
28
|
-
}).catch((
|
|
29
|
-
|
|
30
|
-
vmPromise.reject(...wrappedArgs);
|
|
31
|
-
wrappedArgs.forEach((arg) => arg.dispose());
|
|
111
|
+
}).catch((error) => {
|
|
112
|
+
vmPromise.reject(vm.newError(error?.message || "An error occurred"));
|
|
32
113
|
openPromises[vmPromise._promiseId] = null;
|
|
33
114
|
});
|
|
34
115
|
vmPromise.settled.then(() => {
|
|
@@ -47,19 +128,25 @@ function rejectOpenPromises(vm) {
|
|
|
47
128
|
}
|
|
48
129
|
vm.runtime.executePendingJobs();
|
|
49
130
|
}
|
|
50
|
-
|
|
131
|
+
const isPromise = (value) => {
|
|
132
|
+
return typeof value === "object" && typeof value.then === "function";
|
|
133
|
+
};
|
|
134
|
+
function wrap(vm, value, context, beginAsyncProcess, endAsyncProcess, logger) {
|
|
51
135
|
if (value === null) {
|
|
52
136
|
return null;
|
|
53
|
-
} else if (
|
|
54
|
-
return wrapPromise(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
137
|
+
} else if (isPromise(value)) {
|
|
138
|
+
return wrapPromise(vm, value, beginAsyncProcess, endAsyncProcess, logger);
|
|
55
139
|
} else if (typeof value === "function") {
|
|
56
|
-
return wrapGenericFunction(vm, value, context, beginAsyncProcess, endAsyncProcess);
|
|
140
|
+
return wrapGenericFunction(vm, value, context, beginAsyncProcess, endAsyncProcess, logger);
|
|
57
141
|
} else if (Array.isArray(value)) {
|
|
58
|
-
return wrapArray(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
142
|
+
return wrapArray(vm, value, beginAsyncProcess, endAsyncProcess, logger);
|
|
59
143
|
} else if (value === null) {
|
|
60
144
|
return vm.null;
|
|
145
|
+
} else if (value instanceof Date) {
|
|
146
|
+
const res = vm.evalCode(`new Date(${value.getTime()})`);
|
|
147
|
+
return isSuccess(res) ? res.value : null;
|
|
61
148
|
} else if (typeof value === "object") {
|
|
62
|
-
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
149
|
+
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess, logger);
|
|
63
150
|
} else if (typeof value === "string") {
|
|
64
151
|
return vm.newString(value);
|
|
65
152
|
} else if (typeof value === "number") {
|
|
@@ -67,17 +154,19 @@ function wrap(vm, value, context, beginAsyncProcess, endAsyncProcess) {
|
|
|
67
154
|
} else if (typeof value === "bigint") {
|
|
68
155
|
return vm.newBigInt(value);
|
|
69
156
|
} else if (typeof value === "boolean") {
|
|
70
|
-
|
|
157
|
+
const res = vm.evalCode(value ? "true" : "false");
|
|
158
|
+
return isSuccess(res) ? res.value : null;
|
|
71
159
|
} else if (typeof value === "undefined") {
|
|
72
160
|
return vm.undefined;
|
|
73
161
|
} else {
|
|
162
|
+
console.error("Unknown type", value);
|
|
74
163
|
return null;
|
|
75
164
|
}
|
|
76
165
|
}
|
|
77
|
-
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
166
|
+
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess, logger) {
|
|
78
167
|
const vmObject = vm.newObject();
|
|
79
168
|
for (const [key, value] of Object.entries(obj)) {
|
|
80
|
-
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
169
|
+
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess, logger);
|
|
81
170
|
if (wrappedValue !== null) {
|
|
82
171
|
vm.setProp(vmObject, key, wrappedValue);
|
|
83
172
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
@@ -87,11 +176,11 @@ function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
|
87
176
|
}
|
|
88
177
|
return vmObject;
|
|
89
178
|
}
|
|
90
|
-
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess) {
|
|
179
|
+
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess, logger) {
|
|
91
180
|
const vmObject = vm.newObject();
|
|
92
181
|
whitelist.forEach((key) => {
|
|
93
182
|
const value = obj[key];
|
|
94
|
-
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
183
|
+
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess, logger);
|
|
95
184
|
if (wrappedValue !== null) {
|
|
96
185
|
vm.setProp(vmObject, key, wrappedValue);
|
|
97
186
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
@@ -101,10 +190,10 @@ function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProc
|
|
|
101
190
|
});
|
|
102
191
|
return vmObject;
|
|
103
192
|
}
|
|
104
|
-
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
193
|
+
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess, logger) {
|
|
105
194
|
const vmArray = vm.newArray();
|
|
106
195
|
for (let i = 0; i < arr.length; i++) {
|
|
107
|
-
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess);
|
|
196
|
+
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess, logger);
|
|
108
197
|
vm.setProp(vmArray, i, wrappedValue);
|
|
109
198
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null) {
|
|
110
199
|
wrappedValue.dispose();
|
|
@@ -112,15 +201,47 @@ function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
|
112
201
|
}
|
|
113
202
|
return vmArray;
|
|
114
203
|
}
|
|
115
|
-
function
|
|
204
|
+
function validationDecorator(schema) {
|
|
205
|
+
return function(...args) {
|
|
206
|
+
let argumentObject = {};
|
|
207
|
+
const params = Object.keys(schema.def.shape);
|
|
208
|
+
args.forEach((value, index) => {
|
|
209
|
+
if (index < params.length) {
|
|
210
|
+
argumentObject[params[index]] = value;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
schema.parse(argumentObject);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function wrapGenericFunction(vm, fn, context = void 0, beginAsyncProcess, endAsyncProcess, logger) {
|
|
116
217
|
const vmFn = vm.newFunction(fn.name, (...args) => {
|
|
117
218
|
const unwrappedArgs = args.map(vm.dump);
|
|
118
219
|
try {
|
|
220
|
+
const validatorName = `_params_${fn.name}`;
|
|
221
|
+
const hasValidator = context != void 0 && validatorName in context && "parse" in context[validatorName];
|
|
222
|
+
if (hasValidator) {
|
|
223
|
+
const schema = context[validatorName];
|
|
224
|
+
try {
|
|
225
|
+
const validator = validationDecorator(schema);
|
|
226
|
+
validator(...unwrappedArgs);
|
|
227
|
+
} catch (e) {
|
|
228
|
+
if (e instanceof ZodError) {
|
|
229
|
+
throw new Error(`Parameter validation failed for function "${fn.name}". Expected Parameters: [${Object.keys(schema.def.shape).join(",")}]. Errors:
|
|
230
|
+
${z.prettifyError(e)}`);
|
|
231
|
+
}
|
|
232
|
+
throw new Error(`Parameter validation error calling ${fn.name}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
119
235
|
const result = fn.call(context, ...unwrappedArgs);
|
|
120
|
-
|
|
236
|
+
logger.trace(fn.name, unwrappedArgs, result);
|
|
237
|
+
const wrappedResult = wrap(vm, result, void 0, beginAsyncProcess, endAsyncProcess, logger);
|
|
121
238
|
return wrappedResult;
|
|
122
239
|
} catch (e) {
|
|
123
|
-
|
|
240
|
+
logger.error([e], "sandbox");
|
|
241
|
+
if (e instanceof Error) {
|
|
242
|
+
throw e;
|
|
243
|
+
}
|
|
244
|
+
throw new Error("An exception occurred calling " + fn.name);
|
|
124
245
|
}
|
|
125
246
|
});
|
|
126
247
|
return vmFn;
|
|
@@ -208,34 +329,6 @@ function tsCompile(source, options) {
|
|
|
208
329
|
}
|
|
209
330
|
return ts.transpileModule(source, options).outputText;
|
|
210
331
|
}
|
|
211
|
-
class Logger {
|
|
212
|
-
constructor(debug = false) {
|
|
213
|
-
this.logs = [];
|
|
214
|
-
this.debug = false;
|
|
215
|
-
this.debug = debug;
|
|
216
|
-
}
|
|
217
|
-
log(args, source) {
|
|
218
|
-
if (Array.isArray(args)) {
|
|
219
|
-
this.logs.push({ type: "log", args, source });
|
|
220
|
-
} else {
|
|
221
|
-
this.logs.push({ type: "log", args: [args], source });
|
|
222
|
-
}
|
|
223
|
-
if (this.debug) {
|
|
224
|
-
console.log(`[${source}]:`, ...args);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
error(args, source) {
|
|
228
|
-
if (Array.isArray(args)) {
|
|
229
|
-
this.logs.push({ type: "error", args, source });
|
|
230
|
-
} else {
|
|
231
|
-
this.logs.push({ type: "error", args: [args], source });
|
|
232
|
-
}
|
|
233
|
-
console.error(`[${source}]:`, ...args);
|
|
234
|
-
}
|
|
235
|
-
clear() {
|
|
236
|
-
this.logs = [];
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
332
|
async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug = false) {
|
|
240
333
|
const vm = QuickJS.newContext();
|
|
241
334
|
let errorState = false;
|
|
@@ -277,8 +370,9 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
277
370
|
globalOption.value,
|
|
278
371
|
globalOption.whitelist,
|
|
279
372
|
beginAsyncProcess,
|
|
280
|
-
endAsyncProcess
|
|
281
|
-
|
|
373
|
+
endAsyncProcess,
|
|
374
|
+
logger
|
|
375
|
+
) : wrap(vm, globalOption.value, globalOption, beginAsyncProcess, endAsyncProcess, logger);
|
|
282
376
|
vm.setProp(vm.global, globalNames[i], globalObj);
|
|
283
377
|
globalObj.dispose();
|
|
284
378
|
}
|
|
@@ -286,7 +380,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
286
380
|
const requireHandle = vm.newFunction("require", (...args) => {
|
|
287
381
|
const nativeArgs = args.map(vm.dump);
|
|
288
382
|
if (requireLookup[nativeArgs[0]]) {
|
|
289
|
-
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess);
|
|
383
|
+
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess, logger);
|
|
290
384
|
return returnObj;
|
|
291
385
|
} else {
|
|
292
386
|
return vm.undefined;
|
|
@@ -317,22 +411,22 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
317
411
|
logger.error(["Could not compile:", code], "compiler");
|
|
318
412
|
return {
|
|
319
413
|
success: false,
|
|
320
|
-
logs: logger.
|
|
414
|
+
logs: logger.getLogs()
|
|
321
415
|
};
|
|
322
416
|
}
|
|
323
417
|
} catch (e) {
|
|
324
418
|
logger.error(["Error testing code:", e], "compiler");
|
|
325
419
|
return {
|
|
326
420
|
success: false,
|
|
327
|
-
logs: logger.
|
|
421
|
+
logs: logger.getLogs()
|
|
328
422
|
};
|
|
329
423
|
}
|
|
330
424
|
return {
|
|
331
425
|
success: true,
|
|
332
|
-
logs: logger.
|
|
426
|
+
logs: logger.getLogs()
|
|
333
427
|
};
|
|
334
428
|
},
|
|
335
|
-
runCode: (code) => {
|
|
429
|
+
runCode: async (code) => {
|
|
336
430
|
try {
|
|
337
431
|
logger.clear();
|
|
338
432
|
const compiled = tsCompile(code);
|
|
@@ -340,7 +434,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
340
434
|
logger.error(["Could not compile:", code], "compiler");
|
|
341
435
|
return {
|
|
342
436
|
success: false,
|
|
343
|
-
logs: logger.
|
|
437
|
+
logs: logger.getLogs()
|
|
344
438
|
};
|
|
345
439
|
}
|
|
346
440
|
errorState = false;
|
|
@@ -351,23 +445,37 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
351
445
|
result.error.dispose();
|
|
352
446
|
return {
|
|
353
447
|
success: false,
|
|
354
|
-
logs: logger.
|
|
448
|
+
logs: logger.getPrettyLogs()
|
|
355
449
|
};
|
|
356
450
|
} else if ("value" in result) {
|
|
451
|
+
const settled = vm.resolvePromise(result.value);
|
|
357
452
|
result.value.dispose();
|
|
453
|
+
vm.runtime.executePendingJobs();
|
|
454
|
+
const promiseResult = await settled;
|
|
455
|
+
if (promiseResult.error) {
|
|
456
|
+
const err = vm.dump(promiseResult.error);
|
|
457
|
+
promiseResult.error.dispose();
|
|
458
|
+
const lines = compiled.split("\n").map((l, i) => `${i + 1}: ${l}`);
|
|
459
|
+
logger.error(["Uncaught exception:", err, "\n", lines.join("\n")], "runner");
|
|
460
|
+
return {
|
|
461
|
+
success: false,
|
|
462
|
+
logs: logger.getPrettyLogs()
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
promiseResult.value.dispose();
|
|
358
466
|
if (errorState) {
|
|
359
467
|
const lines = compiled.split("\n").map((line, index) => `${index + 1}: ${line}`);
|
|
360
468
|
logger.error(["An error was reported during execution. Compiled code with line numbers:\n", lines.join("\n")], "runner");
|
|
361
469
|
}
|
|
362
470
|
return {
|
|
363
471
|
success: !errorState,
|
|
364
|
-
logs: logger.
|
|
472
|
+
logs: logger.getPrettyLogs()
|
|
365
473
|
};
|
|
366
474
|
} else {
|
|
367
475
|
logger.error(["Unknown execution result:", result], "runner");
|
|
368
476
|
return {
|
|
369
477
|
success: false,
|
|
370
|
-
logs: logger.
|
|
478
|
+
logs: logger.getPrettyLogs()
|
|
371
479
|
};
|
|
372
480
|
}
|
|
373
481
|
} catch (e) {
|
|
@@ -375,7 +483,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
375
483
|
}
|
|
376
484
|
return {
|
|
377
485
|
success: false,
|
|
378
|
-
logs: logger.
|
|
486
|
+
logs: logger.getLogs()
|
|
379
487
|
};
|
|
380
488
|
}
|
|
381
489
|
};
|
|
@@ -384,13 +492,12 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
384
492
|
require$1("dotenv").config();
|
|
385
493
|
const openai = new OpenAI({ baseURL: process.env.OPENAI_API_BASE_URL || void 0, apiKey: process.env.OPENAI_API_KEY || void 0 });
|
|
386
494
|
let QuickJS = null;
|
|
495
|
+
function createLog(message, source) {
|
|
496
|
+
return { type: "log", args: [message], source };
|
|
497
|
+
}
|
|
387
498
|
const wrapCode = (apiGlobalName, apiFileDefPath, code) => `
|
|
388
499
|
(async () => {
|
|
389
|
-
|
|
390
|
-
${code}
|
|
391
|
-
} catch(err) {
|
|
392
|
-
console.error(err);
|
|
393
|
-
}
|
|
500
|
+
${code}
|
|
394
501
|
})();
|
|
395
502
|
`;
|
|
396
503
|
const wrapCodeBlock = (code, codeType = "") => `
|
|
@@ -404,13 +511,13 @@ function zodParseJSON(schema) {
|
|
|
404
511
|
function createBasePrompt(apiFilePath, apiGlobalName, documentationPath) {
|
|
405
512
|
const apiText = fs.readFileSync(apiFilePath, "utf8");
|
|
406
513
|
const documentationText = documentationPath ? fs.readFileSync(documentationPath, "utf8") : "";
|
|
407
|
-
const createTaskPrompt = fs.readFileSync("
|
|
514
|
+
const createTaskPrompt = fs.readFileSync(path.resolve(__dirname, "../prompts/generate-code-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText).replace("{{API_GLOBAL_NAME}}", apiGlobalName || "");
|
|
408
515
|
return createTaskPrompt;
|
|
409
516
|
}
|
|
410
517
|
const runCodeSchema = z.object({
|
|
411
518
|
code: z.string()
|
|
412
519
|
});
|
|
413
|
-
|
|
520
|
+
z.object({
|
|
414
521
|
code: z.string()
|
|
415
522
|
});
|
|
416
523
|
const submitCodeSchema = z.object({
|
|
@@ -432,34 +539,42 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
432
539
|
if (debug) {
|
|
433
540
|
console.log("Running code...", code);
|
|
434
541
|
}
|
|
542
|
+
const checkRes = await instance.checkCode(code);
|
|
543
|
+
if (!checkRes.success) {
|
|
544
|
+
return {
|
|
545
|
+
success: false,
|
|
546
|
+
reason: "Code check failed",
|
|
547
|
+
logs: checkRes.logs
|
|
548
|
+
};
|
|
549
|
+
}
|
|
435
550
|
const res = await instance.runCode(code);
|
|
436
551
|
if (hideLogsFromAgent) {
|
|
437
552
|
res.logs = [];
|
|
438
553
|
}
|
|
439
554
|
return res;
|
|
440
555
|
},
|
|
441
|
-
description: "
|
|
556
|
+
description: "Check and run the provided code in a sandboxed environment. The code will have access to the API object. Returns the result of the code execution. Use this for testing and experimentation.",
|
|
442
557
|
parse: zodParseJSON(runCodeSchema),
|
|
443
|
-
parameters:
|
|
444
|
-
}
|
|
445
|
-
},
|
|
446
|
-
{
|
|
447
|
-
type: "function",
|
|
448
|
-
function: {
|
|
449
|
-
name: "checkCode",
|
|
450
|
-
// @ts-ignore
|
|
451
|
-
function: async ({ code }) => {
|
|
452
|
-
if (debug) {
|
|
453
|
-
console.log("Checking code...", code);
|
|
454
|
-
}
|
|
455
|
-
const res = await instance.checkCode(code);
|
|
456
|
-
return res;
|
|
457
|
-
},
|
|
458
|
-
description: "Check the provided code for errors or issues without running it. Returns the result of the code check.",
|
|
459
|
-
parse: zodParseJSON(checkCodeSchema),
|
|
460
|
-
parameters: zodToJsonSchema(checkCodeSchema)
|
|
558
|
+
parameters: runCodeSchema.toJSONSchema()
|
|
461
559
|
}
|
|
462
560
|
},
|
|
561
|
+
// {
|
|
562
|
+
// type: "function",
|
|
563
|
+
// function: {
|
|
564
|
+
// name: "checkCode",
|
|
565
|
+
// // @ts-ignore
|
|
566
|
+
// function: async ({code}: {code: string}) => {
|
|
567
|
+
// if(debug) {
|
|
568
|
+
// console.log("Checking code...", code);
|
|
569
|
+
// }
|
|
570
|
+
// const res = await instance.checkCode(code);
|
|
571
|
+
// return res;
|
|
572
|
+
// },
|
|
573
|
+
// description: "Check the provided code for errors or issues without running it. Returns the result of the code check.",
|
|
574
|
+
// parse: zodParseJSON(checkCodeSchema),
|
|
575
|
+
// parameters: checkCodeSchema.toJSONSchema(),
|
|
576
|
+
// }
|
|
577
|
+
// },
|
|
463
578
|
{
|
|
464
579
|
type: "function",
|
|
465
580
|
function: {
|
|
@@ -474,14 +589,18 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
474
589
|
logs: checkRes.logs
|
|
475
590
|
};
|
|
476
591
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
592
|
+
const res = await instance.runCode(code);
|
|
593
|
+
if (hideLogsFromAgent) {
|
|
594
|
+
res.logs = [];
|
|
595
|
+
}
|
|
596
|
+
if (res.success) {
|
|
597
|
+
finalSubmittedCode = code;
|
|
598
|
+
}
|
|
599
|
+
return res;
|
|
481
600
|
},
|
|
482
|
-
description: "Submit the provided code as the final code
|
|
601
|
+
description: "Submit the provided code as a candidate for the final code. The code will be checked and run and output logs and traces will be provided. Check the logs, if satisifed, respond to the user otherwise submit again.",
|
|
483
602
|
parse: zodParseJSON(submitCodeSchema),
|
|
484
|
-
parameters:
|
|
603
|
+
parameters: submitCodeSchema.toJSONSchema()
|
|
485
604
|
}
|
|
486
605
|
}
|
|
487
606
|
];
|
|
@@ -503,17 +622,13 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
503
622
|
...additionalModelOptions
|
|
504
623
|
}).on("message", async (message) => {
|
|
505
624
|
if (debug) {
|
|
506
|
-
|
|
625
|
+
if ("reasoning_content" in message) {
|
|
626
|
+
console.log(message.reasoning_content);
|
|
627
|
+
}
|
|
507
628
|
}
|
|
508
629
|
newHistoryItems.push(message);
|
|
509
630
|
}).on("functionToolCall", (functionCall) => {
|
|
510
|
-
if (debug) {
|
|
511
|
-
console.log("Function Call:", JSON.stringify(functionCall, null, 2));
|
|
512
|
-
}
|
|
513
631
|
}).on("functionToolCallResult", (functionCall) => {
|
|
514
|
-
if (debug) {
|
|
515
|
-
console.log("Function Call Result:", JSON.stringify(functionCall, null, 2));
|
|
516
|
-
}
|
|
517
632
|
});
|
|
518
633
|
const finalContent = await runner.finalContent();
|
|
519
634
|
if (debug) {
|
|
@@ -617,7 +732,7 @@ async function createWithAPI(options) {
|
|
|
617
732
|
console.error("Unknown failure checking code");
|
|
618
733
|
return {
|
|
619
734
|
success: false,
|
|
620
|
-
logs: []
|
|
735
|
+
logs: [createLog("Unknown failure checking code", "compiler")]
|
|
621
736
|
};
|
|
622
737
|
}
|
|
623
738
|
if (debug) {
|
|
@@ -658,7 +773,7 @@ async function createWithAPI(options) {
|
|
|
658
773
|
};
|
|
659
774
|
}
|
|
660
775
|
}
|
|
661
|
-
const { vm, runCode:
|
|
776
|
+
const { vm, runCode: sandbox_runCode, isAsyncProcessRunning } = await createSandbox(QuickJS, apiExports ? {
|
|
662
777
|
[apiDefFilePath]: apiExports
|
|
663
778
|
} : void 0, {
|
|
664
779
|
...apiGlobals,
|
|
@@ -671,7 +786,7 @@ async function createWithAPI(options) {
|
|
|
671
786
|
if (debug) {
|
|
672
787
|
console.log("Running Code:\n", code);
|
|
673
788
|
}
|
|
674
|
-
const res = await
|
|
789
|
+
const res = await sandbox_runCode(wrapCode(apiGlobalName, apiDefFilePath, code));
|
|
675
790
|
if (!res) {
|
|
676
791
|
console.error("Unknown failure running task");
|
|
677
792
|
return {
|
|
@@ -702,27 +817,35 @@ async function createWithAPI(options) {
|
|
|
702
817
|
// generates code and runs it in one step
|
|
703
818
|
processRequest: async function(userQuery, currentContext = void 0) {
|
|
704
819
|
if (debug) {
|
|
705
|
-
console.log("Query:", userQuery);
|
|
820
|
+
console.log("[debug] Query:", userQuery);
|
|
706
821
|
}
|
|
707
822
|
console.time("Generate Task");
|
|
823
|
+
const prompt = createTaskPrompt.replace("{{CONTEXT}}", currentContext ? JSON.stringify(currentContext, null, 2) : "");
|
|
708
824
|
const generatedCode = await generateCode(
|
|
709
825
|
instance,
|
|
710
826
|
userQuery,
|
|
711
827
|
[],
|
|
712
|
-
|
|
828
|
+
prompt,
|
|
713
829
|
debug,
|
|
714
830
|
hideLogsFromAgent,
|
|
715
831
|
model,
|
|
716
832
|
additionalModelOptions
|
|
717
833
|
);
|
|
718
834
|
console.timeEnd("Generate Task");
|
|
719
|
-
console.
|
|
835
|
+
console.log(`generated code result
|
|
836
|
+
Success?: ${generatedCode?.success}
|
|
837
|
+
Comments: ${generatedCode?.comments}
|
|
838
|
+
Running Code...`);
|
|
839
|
+
console.time("Run Code took");
|
|
720
840
|
if (generatedCode?.code) {
|
|
721
|
-
await instance.runCode(generatedCode.code);
|
|
841
|
+
const codeRunResult = await instance.runCode(generatedCode.code);
|
|
842
|
+
if (!codeRunResult.success) {
|
|
843
|
+
console.error("Error running generated code");
|
|
844
|
+
}
|
|
722
845
|
} else {
|
|
723
846
|
console.error("No code generated", generatedCode);
|
|
724
847
|
}
|
|
725
|
-
console.timeEnd("Run Code");
|
|
848
|
+
console.timeEnd("Run Code took");
|
|
726
849
|
return generatedCode;
|
|
727
850
|
}
|
|
728
851
|
};
|
package/example/example1.ts
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
|
-
import { AIMyAPI } from "../src";
|
|
2
|
-
import { API } from "./sales_api_impl";
|
|
3
|
-
|
|
4
|
-
// Simpler example using no support for chat history;
|
|
5
|
-
|
|
6
|
-
(async () => {
|
|
7
|
-
const api = new API();
|
|
8
|
-
|
|
9
|
-
const aimyapi = await AIMyAPI.createWithAPI({
|
|
10
|
-
apiObject: api,
|
|
11
|
-
apiGlobalName: "salesApi", // Should match whatever you declared as your global in your api.
|
|
12
|
-
apiDefFilePath: "./example/sales_api.ts",
|
|
13
|
-
apiDocsPath: "./example/sales_api.md",
|
|
14
|
-
debug: false,
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
console.log(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
await aimyapi.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
import { AIMyAPI } from "../src";
|
|
2
|
+
import { API } from "./sales_api_impl";
|
|
3
|
+
|
|
4
|
+
// Simpler example using no support for chat history;
|
|
5
|
+
|
|
6
|
+
(async () => {
|
|
7
|
+
const api = new API();
|
|
8
|
+
|
|
9
|
+
const aimyapi = await AIMyAPI.createWithAPI({
|
|
10
|
+
apiObject: api,
|
|
11
|
+
apiGlobalName: "salesApi", // Should match whatever you declared as your global in your api.
|
|
12
|
+
apiDefFilePath: "./example/sales_api.ts",
|
|
13
|
+
apiDocsPath: "./example/sales_api.md",
|
|
14
|
+
debug: false,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// test the sandbox:
|
|
18
|
+
await aimyapi.runCode(`await salesApi.display("Hello from the sandbox! Here is some sales data:");`);
|
|
19
|
+
|
|
20
|
+
console.log("Test parameter validation (should fail)");
|
|
21
|
+
const failResult = await aimyapi.runCode(`await salesApi.sendEmail("fail");`);
|
|
22
|
+
console.log(JSON.stringify(failResult, null, 2));
|
|
23
|
+
console.log("Test parameter validation (should pass)");
|
|
24
|
+
await aimyapi.runCode(`await salesApi.sendEmail("to@email.com", "Your emails", "body text");`);
|
|
25
|
+
|
|
26
|
+
await aimyapi.runCode(`await salesApi.display(salesApi.getDate());`);
|
|
27
|
+
|
|
28
|
+
// test code writing:
|
|
29
|
+
const queries = [ "Display 'hello' three times.", "What month had the highest sales in 2020 for any business unit?", "Which business unit had the highest sales in 2020? Display the totals for each business unit", "Compute the total sales for each month in 2020 then email the top 3 to test@email.com"]
|
|
30
|
+
|
|
31
|
+
for(const k in queries) {
|
|
32
|
+
const query = queries[k];
|
|
33
|
+
console.log(`Query: ${query}`);
|
|
34
|
+
const testResult = await aimyapi.processRequest(query);
|
|
35
|
+
if(testResult?.code)
|
|
36
|
+
console.log("Code:", testResult.code)
|
|
37
|
+
else {
|
|
38
|
+
console.log(testResult);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
})();
|