aimyapi 1.0.9 → 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/README.md +28 -2
- package/dist/index.cjs +232 -111
- 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 +232 -111
- package/dist/index.mjs +234 -113
- package/example/example1.ts +21 -10
- package/example/sales_api.md +1 -5
- package/example/sales_api.ts +4 -2
- package/example/sales_api_impl.ts +18 -4
- package/package.json +2 -3
- package/prompts/generate-code-prompt.md +37 -0
- package/src/index.ts +519 -495
- 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 +91 -46
- package/src/sandbox.ts +254 -277
- package/src/utils.ts +31 -1
- 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,21 +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;
|
|
61
145
|
} else if (value instanceof Date) {
|
|
62
|
-
|
|
146
|
+
const res = vm.evalCode(`new Date(${value.getTime()})`);
|
|
147
|
+
return isSuccess(res) ? res.value : null;
|
|
63
148
|
} else if (typeof value === "object") {
|
|
64
|
-
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
149
|
+
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess, logger);
|
|
65
150
|
} else if (typeof value === "string") {
|
|
66
151
|
return vm.newString(value);
|
|
67
152
|
} else if (typeof value === "number") {
|
|
@@ -69,17 +154,19 @@ function wrap(vm, value, context, beginAsyncProcess, endAsyncProcess) {
|
|
|
69
154
|
} else if (typeof value === "bigint") {
|
|
70
155
|
return vm.newBigInt(value);
|
|
71
156
|
} else if (typeof value === "boolean") {
|
|
72
|
-
|
|
157
|
+
const res = vm.evalCode(value ? "true" : "false");
|
|
158
|
+
return isSuccess(res) ? res.value : null;
|
|
73
159
|
} else if (typeof value === "undefined") {
|
|
74
160
|
return vm.undefined;
|
|
75
161
|
} else {
|
|
162
|
+
console.error("Unknown type", value);
|
|
76
163
|
return null;
|
|
77
164
|
}
|
|
78
165
|
}
|
|
79
|
-
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
166
|
+
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess, logger) {
|
|
80
167
|
const vmObject = vm.newObject();
|
|
81
168
|
for (const [key, value] of Object.entries(obj)) {
|
|
82
|
-
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
169
|
+
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess, logger);
|
|
83
170
|
if (wrappedValue !== null) {
|
|
84
171
|
vm.setProp(vmObject, key, wrappedValue);
|
|
85
172
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
@@ -89,11 +176,11 @@ function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
|
89
176
|
}
|
|
90
177
|
return vmObject;
|
|
91
178
|
}
|
|
92
|
-
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess) {
|
|
179
|
+
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess, logger) {
|
|
93
180
|
const vmObject = vm.newObject();
|
|
94
181
|
whitelist.forEach((key) => {
|
|
95
182
|
const value = obj[key];
|
|
96
|
-
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
183
|
+
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess, logger);
|
|
97
184
|
if (wrappedValue !== null) {
|
|
98
185
|
vm.setProp(vmObject, key, wrappedValue);
|
|
99
186
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
@@ -103,10 +190,10 @@ function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProc
|
|
|
103
190
|
});
|
|
104
191
|
return vmObject;
|
|
105
192
|
}
|
|
106
|
-
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
193
|
+
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess, logger) {
|
|
107
194
|
const vmArray = vm.newArray();
|
|
108
195
|
for (let i = 0; i < arr.length; i++) {
|
|
109
|
-
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess);
|
|
196
|
+
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess, logger);
|
|
110
197
|
vm.setProp(vmArray, i, wrappedValue);
|
|
111
198
|
if (wrappedValue != vm.undefined && wrappedValue != vm.null) {
|
|
112
199
|
wrappedValue.dispose();
|
|
@@ -114,15 +201,47 @@ function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
|
114
201
|
}
|
|
115
202
|
return vmArray;
|
|
116
203
|
}
|
|
117
|
-
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) {
|
|
118
217
|
const vmFn = vm.newFunction(fn.name, (...args) => {
|
|
119
218
|
const unwrappedArgs = args.map(vm.dump);
|
|
120
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
|
+
}
|
|
121
235
|
const result = fn.call(context, ...unwrappedArgs);
|
|
122
|
-
|
|
236
|
+
logger.trace(fn.name, unwrappedArgs, result);
|
|
237
|
+
const wrappedResult = wrap(vm, result, void 0, beginAsyncProcess, endAsyncProcess, logger);
|
|
123
238
|
return wrappedResult;
|
|
124
239
|
} catch (e) {
|
|
125
|
-
|
|
240
|
+
logger.error([e], "sandbox");
|
|
241
|
+
if (e instanceof Error) {
|
|
242
|
+
throw e;
|
|
243
|
+
}
|
|
244
|
+
throw new Error("An exception occurred calling " + fn.name);
|
|
126
245
|
}
|
|
127
246
|
});
|
|
128
247
|
return vmFn;
|
|
@@ -210,34 +329,6 @@ function tsCompile(source, options) {
|
|
|
210
329
|
}
|
|
211
330
|
return ts.transpileModule(source, options).outputText;
|
|
212
331
|
}
|
|
213
|
-
class Logger {
|
|
214
|
-
constructor(debug = false) {
|
|
215
|
-
this.logs = [];
|
|
216
|
-
this.debug = false;
|
|
217
|
-
this.debug = debug;
|
|
218
|
-
}
|
|
219
|
-
log(args, source) {
|
|
220
|
-
if (Array.isArray(args)) {
|
|
221
|
-
this.logs.push({ type: "log", args, source });
|
|
222
|
-
} else {
|
|
223
|
-
this.logs.push({ type: "log", args: [args], source });
|
|
224
|
-
}
|
|
225
|
-
if (this.debug) {
|
|
226
|
-
console.log(`[${source}]:`, ...args);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
error(args, source) {
|
|
230
|
-
if (Array.isArray(args)) {
|
|
231
|
-
this.logs.push({ type: "error", args, source });
|
|
232
|
-
} else {
|
|
233
|
-
this.logs.push({ type: "error", args: [args], source });
|
|
234
|
-
}
|
|
235
|
-
console.error(`[${source}]:`, ...args);
|
|
236
|
-
}
|
|
237
|
-
clear() {
|
|
238
|
-
this.logs = [];
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
332
|
async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug = false) {
|
|
242
333
|
const vm = QuickJS.newContext();
|
|
243
334
|
let errorState = false;
|
|
@@ -279,8 +370,9 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
279
370
|
globalOption.value,
|
|
280
371
|
globalOption.whitelist,
|
|
281
372
|
beginAsyncProcess,
|
|
282
|
-
endAsyncProcess
|
|
283
|
-
|
|
373
|
+
endAsyncProcess,
|
|
374
|
+
logger
|
|
375
|
+
) : wrap(vm, globalOption.value, globalOption, beginAsyncProcess, endAsyncProcess, logger);
|
|
284
376
|
vm.setProp(vm.global, globalNames[i], globalObj);
|
|
285
377
|
globalObj.dispose();
|
|
286
378
|
}
|
|
@@ -288,7 +380,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
288
380
|
const requireHandle = vm.newFunction("require", (...args) => {
|
|
289
381
|
const nativeArgs = args.map(vm.dump);
|
|
290
382
|
if (requireLookup[nativeArgs[0]]) {
|
|
291
|
-
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess);
|
|
383
|
+
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess, logger);
|
|
292
384
|
return returnObj;
|
|
293
385
|
} else {
|
|
294
386
|
return vm.undefined;
|
|
@@ -319,22 +411,22 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
319
411
|
logger.error(["Could not compile:", code], "compiler");
|
|
320
412
|
return {
|
|
321
413
|
success: false,
|
|
322
|
-
logs: logger.
|
|
414
|
+
logs: logger.getLogs()
|
|
323
415
|
};
|
|
324
416
|
}
|
|
325
417
|
} catch (e) {
|
|
326
418
|
logger.error(["Error testing code:", e], "compiler");
|
|
327
419
|
return {
|
|
328
420
|
success: false,
|
|
329
|
-
logs: logger.
|
|
421
|
+
logs: logger.getLogs()
|
|
330
422
|
};
|
|
331
423
|
}
|
|
332
424
|
return {
|
|
333
425
|
success: true,
|
|
334
|
-
logs: logger.
|
|
426
|
+
logs: logger.getLogs()
|
|
335
427
|
};
|
|
336
428
|
},
|
|
337
|
-
runCode: (code) => {
|
|
429
|
+
runCode: async (code) => {
|
|
338
430
|
try {
|
|
339
431
|
logger.clear();
|
|
340
432
|
const compiled = tsCompile(code);
|
|
@@ -342,7 +434,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
342
434
|
logger.error(["Could not compile:", code], "compiler");
|
|
343
435
|
return {
|
|
344
436
|
success: false,
|
|
345
|
-
logs: logger.
|
|
437
|
+
logs: logger.getLogs()
|
|
346
438
|
};
|
|
347
439
|
}
|
|
348
440
|
errorState = false;
|
|
@@ -353,23 +445,37 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
353
445
|
result.error.dispose();
|
|
354
446
|
return {
|
|
355
447
|
success: false,
|
|
356
|
-
logs: logger.
|
|
448
|
+
logs: logger.getPrettyLogs()
|
|
357
449
|
};
|
|
358
450
|
} else if ("value" in result) {
|
|
451
|
+
const settled = vm.resolvePromise(result.value);
|
|
359
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();
|
|
360
466
|
if (errorState) {
|
|
361
467
|
const lines = compiled.split("\n").map((line, index) => `${index + 1}: ${line}`);
|
|
362
468
|
logger.error(["An error was reported during execution. Compiled code with line numbers:\n", lines.join("\n")], "runner");
|
|
363
469
|
}
|
|
364
470
|
return {
|
|
365
471
|
success: !errorState,
|
|
366
|
-
logs: logger.
|
|
472
|
+
logs: logger.getPrettyLogs()
|
|
367
473
|
};
|
|
368
474
|
} else {
|
|
369
475
|
logger.error(["Unknown execution result:", result], "runner");
|
|
370
476
|
return {
|
|
371
477
|
success: false,
|
|
372
|
-
logs: logger.
|
|
478
|
+
logs: logger.getPrettyLogs()
|
|
373
479
|
};
|
|
374
480
|
}
|
|
375
481
|
} catch (e) {
|
|
@@ -377,7 +483,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
377
483
|
}
|
|
378
484
|
return {
|
|
379
485
|
success: false,
|
|
380
|
-
logs: logger.
|
|
486
|
+
logs: logger.getLogs()
|
|
381
487
|
};
|
|
382
488
|
}
|
|
383
489
|
};
|
|
@@ -386,13 +492,12 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
|
|
|
386
492
|
require$1("dotenv").config();
|
|
387
493
|
const openai = new OpenAI({ baseURL: process.env.OPENAI_API_BASE_URL || void 0, apiKey: process.env.OPENAI_API_KEY || void 0 });
|
|
388
494
|
let QuickJS = null;
|
|
495
|
+
function createLog(message, source) {
|
|
496
|
+
return { type: "log", args: [message], source };
|
|
497
|
+
}
|
|
389
498
|
const wrapCode = (apiGlobalName, apiFileDefPath, code) => `
|
|
390
499
|
(async () => {
|
|
391
|
-
|
|
392
|
-
${code}
|
|
393
|
-
} catch(err) {
|
|
394
|
-
console.error(err);
|
|
395
|
-
}
|
|
500
|
+
${code}
|
|
396
501
|
})();
|
|
397
502
|
`;
|
|
398
503
|
const wrapCodeBlock = (code, codeType = "") => `
|
|
@@ -406,13 +511,13 @@ function zodParseJSON(schema) {
|
|
|
406
511
|
function createBasePrompt(apiFilePath, apiGlobalName, documentationPath) {
|
|
407
512
|
const apiText = fs.readFileSync(apiFilePath, "utf8");
|
|
408
513
|
const documentationText = documentationPath ? fs.readFileSync(documentationPath, "utf8") : "";
|
|
409
|
-
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 || "");
|
|
410
515
|
return createTaskPrompt;
|
|
411
516
|
}
|
|
412
517
|
const runCodeSchema = z.object({
|
|
413
518
|
code: z.string()
|
|
414
519
|
});
|
|
415
|
-
|
|
520
|
+
z.object({
|
|
416
521
|
code: z.string()
|
|
417
522
|
});
|
|
418
523
|
const submitCodeSchema = z.object({
|
|
@@ -434,34 +539,42 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
434
539
|
if (debug) {
|
|
435
540
|
console.log("Running code...", code);
|
|
436
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
|
+
}
|
|
437
550
|
const res = await instance.runCode(code);
|
|
438
551
|
if (hideLogsFromAgent) {
|
|
439
552
|
res.logs = [];
|
|
440
553
|
}
|
|
441
554
|
return res;
|
|
442
555
|
},
|
|
443
|
-
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.",
|
|
444
557
|
parse: zodParseJSON(runCodeSchema),
|
|
445
|
-
parameters:
|
|
446
|
-
}
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
type: "function",
|
|
450
|
-
function: {
|
|
451
|
-
name: "checkCode",
|
|
452
|
-
// @ts-ignore
|
|
453
|
-
function: async ({ code }) => {
|
|
454
|
-
if (debug) {
|
|
455
|
-
console.log("Checking code...", code);
|
|
456
|
-
}
|
|
457
|
-
const res = await instance.checkCode(code);
|
|
458
|
-
return res;
|
|
459
|
-
},
|
|
460
|
-
description: "Check the provided code for errors or issues without running it. Returns the result of the code check.",
|
|
461
|
-
parse: zodParseJSON(checkCodeSchema),
|
|
462
|
-
parameters: zodToJsonSchema(checkCodeSchema)
|
|
558
|
+
parameters: runCodeSchema.toJSONSchema()
|
|
463
559
|
}
|
|
464
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
|
+
// },
|
|
465
578
|
{
|
|
466
579
|
type: "function",
|
|
467
580
|
function: {
|
|
@@ -476,14 +589,18 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
476
589
|
logs: checkRes.logs
|
|
477
590
|
};
|
|
478
591
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
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;
|
|
483
600
|
},
|
|
484
|
-
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.",
|
|
485
602
|
parse: zodParseJSON(submitCodeSchema),
|
|
486
|
-
parameters:
|
|
603
|
+
parameters: submitCodeSchema.toJSONSchema()
|
|
487
604
|
}
|
|
488
605
|
}
|
|
489
606
|
];
|
|
@@ -505,17 +622,13 @@ const generateCode = async function(instance, queryText, userChatHistory, create
|
|
|
505
622
|
...additionalModelOptions
|
|
506
623
|
}).on("message", async (message) => {
|
|
507
624
|
if (debug) {
|
|
508
|
-
|
|
625
|
+
if ("reasoning_content" in message) {
|
|
626
|
+
console.log(message.reasoning_content);
|
|
627
|
+
}
|
|
509
628
|
}
|
|
510
629
|
newHistoryItems.push(message);
|
|
511
630
|
}).on("functionToolCall", (functionCall) => {
|
|
512
|
-
if (debug) {
|
|
513
|
-
console.log("Function Call:", JSON.stringify(functionCall, null, 2));
|
|
514
|
-
}
|
|
515
631
|
}).on("functionToolCallResult", (functionCall) => {
|
|
516
|
-
if (debug) {
|
|
517
|
-
console.log("Function Call Result:", JSON.stringify(functionCall, null, 2));
|
|
518
|
-
}
|
|
519
632
|
});
|
|
520
633
|
const finalContent = await runner.finalContent();
|
|
521
634
|
if (debug) {
|
|
@@ -619,7 +732,7 @@ async function createWithAPI(options) {
|
|
|
619
732
|
console.error("Unknown failure checking code");
|
|
620
733
|
return {
|
|
621
734
|
success: false,
|
|
622
|
-
logs: []
|
|
735
|
+
logs: [createLog("Unknown failure checking code", "compiler")]
|
|
623
736
|
};
|
|
624
737
|
}
|
|
625
738
|
if (debug) {
|
|
@@ -660,7 +773,7 @@ async function createWithAPI(options) {
|
|
|
660
773
|
};
|
|
661
774
|
}
|
|
662
775
|
}
|
|
663
|
-
const { vm, runCode:
|
|
776
|
+
const { vm, runCode: sandbox_runCode, isAsyncProcessRunning } = await createSandbox(QuickJS, apiExports ? {
|
|
664
777
|
[apiDefFilePath]: apiExports
|
|
665
778
|
} : void 0, {
|
|
666
779
|
...apiGlobals,
|
|
@@ -673,7 +786,7 @@ async function createWithAPI(options) {
|
|
|
673
786
|
if (debug) {
|
|
674
787
|
console.log("Running Code:\n", code);
|
|
675
788
|
}
|
|
676
|
-
const res = await
|
|
789
|
+
const res = await sandbox_runCode(wrapCode(apiGlobalName, apiDefFilePath, code));
|
|
677
790
|
if (!res) {
|
|
678
791
|
console.error("Unknown failure running task");
|
|
679
792
|
return {
|
|
@@ -704,27 +817,35 @@ async function createWithAPI(options) {
|
|
|
704
817
|
// generates code and runs it in one step
|
|
705
818
|
processRequest: async function(userQuery, currentContext = void 0) {
|
|
706
819
|
if (debug) {
|
|
707
|
-
console.log("Query:", userQuery);
|
|
820
|
+
console.log("[debug] Query:", userQuery);
|
|
708
821
|
}
|
|
709
822
|
console.time("Generate Task");
|
|
823
|
+
const prompt = createTaskPrompt.replace("{{CONTEXT}}", currentContext ? JSON.stringify(currentContext, null, 2) : "");
|
|
710
824
|
const generatedCode = await generateCode(
|
|
711
825
|
instance,
|
|
712
826
|
userQuery,
|
|
713
827
|
[],
|
|
714
|
-
|
|
828
|
+
prompt,
|
|
715
829
|
debug,
|
|
716
830
|
hideLogsFromAgent,
|
|
717
831
|
model,
|
|
718
832
|
additionalModelOptions
|
|
719
833
|
);
|
|
720
834
|
console.timeEnd("Generate Task");
|
|
721
|
-
console.
|
|
835
|
+
console.log(`generated code result
|
|
836
|
+
Success?: ${generatedCode?.success}
|
|
837
|
+
Comments: ${generatedCode?.comments}
|
|
838
|
+
Running Code...`);
|
|
839
|
+
console.time("Run Code took");
|
|
722
840
|
if (generatedCode?.code) {
|
|
723
|
-
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
|
+
}
|
|
724
845
|
} else {
|
|
725
846
|
console.error("No code generated", generatedCode);
|
|
726
847
|
}
|
|
727
|
-
console.timeEnd("Run Code");
|
|
848
|
+
console.timeEnd("Run Code took");
|
|
728
849
|
return generatedCode;
|
|
729
850
|
}
|
|
730
851
|
};
|
package/example/example1.ts
CHANGED
|
@@ -14,18 +14,29 @@ import { API } from "./sales_api_impl";
|
|
|
14
14
|
debug: false,
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// test the sandbox:
|
|
18
|
+
await aimyapi.runCode(`await salesApi.display("Hello from the sandbox! Here is some sales data:");`);
|
|
18
19
|
|
|
19
|
-
console.log("
|
|
20
|
-
await aimyapi.
|
|
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");`);
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
await aimyapi.processRequest("What was our best month in 2020");
|
|
26
|
+
await aimyapi.runCode(`await salesApi.display(salesApi.getDate());`);
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
}
|
|
28
41
|
|
|
29
|
-
console.log("Compute the total sales for each month in 2020 then email the top 3 to test@email.com")
|
|
30
|
-
await aimyapi.processRequest("Compute the total sales for each month in 2020 then email the top 3 to test@email.com");
|
|
31
42
|
})();
|
package/example/sales_api.md
CHANGED
package/example/sales_api.ts
CHANGED
|
@@ -12,11 +12,13 @@ export interface APIInterface {
|
|
|
12
12
|
|
|
13
13
|
sendEmail(to: string, subject: string, body: string): Promise<void>;
|
|
14
14
|
|
|
15
|
+
getDate(): Date;
|
|
16
|
+
|
|
15
17
|
getSalesData(): SalesData[];
|
|
16
18
|
// Returns an array of sales data.
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
+
display(text: string): void;
|
|
21
|
+
// display the specified text to the user. Always use this to respond with your result.
|
|
20
22
|
|
|
21
23
|
delay(milliseconds: number): Promise<void>;
|
|
22
24
|
// waits for the specified number of milliseconds before resolving the promise.
|