aimyapi 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/.prettierrc +3 -0
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/example/example1.d.ts +1 -0
- package/dist/example/example1.js +52 -0
- package/dist/example/example2.d.ts +1 -0
- package/dist/example/example2.js +66 -0
- package/dist/example/example3.d.ts +1 -0
- package/dist/example/example3.js +79 -0
- package/dist/example/ordering_api.d.ts +36 -0
- package/dist/example/ordering_api.js +125 -0
- package/dist/example/ordering_api_impl.d.ts +23 -0
- package/dist/example/ordering_api_impl.js +128 -0
- package/dist/example/sales_api.d.ts +16 -0
- package/dist/example/sales_api.js +5 -0
- package/dist/example/sales_api_impl.d.ts +7 -0
- package/dist/example/sales_api_impl.js +59 -0
- package/dist/lib/index.d.ts +26 -0
- package/dist/lib/index.js +179 -0
- package/dist/lib/sandbox-wrappers.d.ts +9 -0
- package/dist/lib/sandbox-wrappers.js +237 -0
- package/dist/lib/sandbox.d.ts +14 -0
- package/dist/lib/sandbox.js +161 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +7 -0
- package/example/example1.ts +33 -0
- package/example/example2.ts +50 -0
- package/example/example3.ts +64 -0
- package/example/ordering_api.md +106 -0
- package/example/ordering_api.ts +194 -0
- package/example/ordering_api_impl.ts +194 -0
- package/example/sales_api.md +15 -0
- package/example/sales_api.ts +29 -0
- package/example/sales_api_impl.ts +60 -0
- package/lib/index.ts +247 -0
- package/lib/sandbox-wrappers.ts +250 -0
- package/lib/sandbox.ts +184 -0
- package/lib/utils.ts +3 -0
- package/package.json +41 -0
- package/prompts/create-task-prompt.md +21 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderingAPI = void 0;
|
|
4
|
+
const utils_1 = require("../lib/utils");
|
|
5
|
+
const ordering_api_1 = require("./ordering_api");
|
|
6
|
+
// TODO: make functions to print out an item, and print out the current order with the price totals.
|
|
7
|
+
class OrderingAPI {
|
|
8
|
+
constructor() {
|
|
9
|
+
this._order = [];
|
|
10
|
+
this._lastOrderIdNumber = 0;
|
|
11
|
+
this._isCompleted = false;
|
|
12
|
+
this._history = [];
|
|
13
|
+
}
|
|
14
|
+
// Mock implementation, doesn't actually send an email
|
|
15
|
+
sendEmail(to, subject, body) {
|
|
16
|
+
console.log(`Sending email to "${to}" with subject "${subject}" and body\n"${body}"`);
|
|
17
|
+
return (0, utils_1.delay)(1000);
|
|
18
|
+
}
|
|
19
|
+
respondToUser(text) {
|
|
20
|
+
console.log(text);
|
|
21
|
+
this._history.push({
|
|
22
|
+
role: "assistant",
|
|
23
|
+
content: "Response output: " + text,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
delay(milliseconds) {
|
|
27
|
+
return (0, utils_1.delay)(milliseconds);
|
|
28
|
+
}
|
|
29
|
+
getCurrentOrder() {
|
|
30
|
+
return this._order;
|
|
31
|
+
}
|
|
32
|
+
// addItemToOrder(item: MenuItemBase) {
|
|
33
|
+
// item.orderId = "" + (this._lastOrderIdNumber++);
|
|
34
|
+
// this._order.push(item);
|
|
35
|
+
// }
|
|
36
|
+
getCustomizationByName(itemName, name) {
|
|
37
|
+
const item = ordering_api_1.Menu.find((item) => item.name === itemName);
|
|
38
|
+
if (!item) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return item.allowedCustomizations.find((customization) => customization.name === name);
|
|
42
|
+
}
|
|
43
|
+
addItemToOrder(itemName, customizationNames, toppings) {
|
|
44
|
+
const item = ordering_api_1.Menu.find((item) => item.name === itemName);
|
|
45
|
+
if (!item) {
|
|
46
|
+
throw new Error(`Item with name "${itemName}" not found`);
|
|
47
|
+
}
|
|
48
|
+
const customizations = customizationNames
|
|
49
|
+
.map((customizationName) => {
|
|
50
|
+
return this.getCustomizationByName(itemName, customizationName);
|
|
51
|
+
})
|
|
52
|
+
.filter((customization) => customization !== undefined);
|
|
53
|
+
const newItem = {
|
|
54
|
+
...item,
|
|
55
|
+
customizations,
|
|
56
|
+
toppings: toppings,
|
|
57
|
+
orderId: "" + this._lastOrderIdNumber++,
|
|
58
|
+
};
|
|
59
|
+
this._order.push(newItem);
|
|
60
|
+
this.respondToUser(`Added ${itemName} with id ${newItem.orderId}`);
|
|
61
|
+
this.displayItem(newItem);
|
|
62
|
+
}
|
|
63
|
+
getItemInOrder(itemOrderId) {
|
|
64
|
+
const item = this._order.find((item) => item.orderId === itemOrderId);
|
|
65
|
+
if (!item) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return item;
|
|
69
|
+
}
|
|
70
|
+
removeItemFromOrder(itemOrderId) {
|
|
71
|
+
this._order = this._order.filter((item) => item.orderId !== itemOrderId);
|
|
72
|
+
this.respondToUser(`Removed item ${itemOrderId}`);
|
|
73
|
+
}
|
|
74
|
+
modifyItemInOrder(itemOrderId, customizationNames, toppings) {
|
|
75
|
+
const existingIndex = this._order.findIndex((item) => item.orderId === itemOrderId);
|
|
76
|
+
if (existingIndex !== -1) {
|
|
77
|
+
const customizations = customizationNames
|
|
78
|
+
.map((customizationName) => {
|
|
79
|
+
return this.getCustomizationByName(this._order[existingIndex].name, customizationName);
|
|
80
|
+
})
|
|
81
|
+
.filter((customization) => customization !== undefined);
|
|
82
|
+
this._order[existingIndex].customizations = customizations;
|
|
83
|
+
this._order[existingIndex].toppings = toppings;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw new Error(`Item with id #"${itemOrderId}" not found in order`);
|
|
87
|
+
}
|
|
88
|
+
this.respondToUser(`Modified item ${itemOrderId}`);
|
|
89
|
+
}
|
|
90
|
+
getOrderTotal() {
|
|
91
|
+
const total = this._order.reduce((total, item) => {
|
|
92
|
+
const customizationTotal = item.customizations.reduce((total, customization) => {
|
|
93
|
+
return total + customization?.priceAdjustment || 0;
|
|
94
|
+
}, 0);
|
|
95
|
+
return total + item.price + customizationTotal;
|
|
96
|
+
}, 0);
|
|
97
|
+
return total;
|
|
98
|
+
}
|
|
99
|
+
completeOrder() {
|
|
100
|
+
this.displayOrder();
|
|
101
|
+
this.respondToUser("Order completed!");
|
|
102
|
+
this._lastOrderIdNumber = 0;
|
|
103
|
+
// clear history
|
|
104
|
+
this._history = [];
|
|
105
|
+
this._isCompleted = true;
|
|
106
|
+
}
|
|
107
|
+
displayItem(item) {
|
|
108
|
+
this.respondToUser(`\t#${item.orderId || ""} ${item.name}...\t\t$${item.price.toFixed(2)}`);
|
|
109
|
+
item.toppings.forEach((topping) => {
|
|
110
|
+
this.respondToUser(`\t\t${topping}`);
|
|
111
|
+
});
|
|
112
|
+
item.customizations.forEach((customization) => {
|
|
113
|
+
this.respondToUser(`\t\t${customization.name}...\t$${customization.priceAdjustment.toFixed(2)}`);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
displayOrder() {
|
|
117
|
+
this.respondToUser("----\n\nDisplaying order:\n\n");
|
|
118
|
+
this._order.forEach((item) => this.displayItem(item));
|
|
119
|
+
this.respondToUser(`--\tTotal:\t\t$${this.getOrderTotal()}`);
|
|
120
|
+
}
|
|
121
|
+
_addMessageToHistory(message) {
|
|
122
|
+
this._history.push(message);
|
|
123
|
+
}
|
|
124
|
+
_getHistory() {
|
|
125
|
+
return this._history;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.OrderingAPI = OrderingAPI;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const API_VERSION = "1.0.1";
|
|
2
|
+
export interface SalesData {
|
|
3
|
+
sales: number;
|
|
4
|
+
month: number;
|
|
5
|
+
year: number;
|
|
6
|
+
businessUnit: "Advertising" | "Hardware" | "Software";
|
|
7
|
+
}
|
|
8
|
+
export interface APIInterface {
|
|
9
|
+
sendEmail(to: string, subject: string, body: string): Promise<void>;
|
|
10
|
+
getSalesData(): SalesData[];
|
|
11
|
+
print(text: string): void;
|
|
12
|
+
delay(milliseconds: number): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
declare global {
|
|
15
|
+
var api: APIInterface;
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { APIInterface, SalesData } from "./sales_api";
|
|
2
|
+
export declare class API implements APIInterface {
|
|
3
|
+
sendEmail(to: string, subject: string, body: string): Promise<void>;
|
|
4
|
+
getSalesData(): SalesData[];
|
|
5
|
+
print(text: string): void;
|
|
6
|
+
delay(milliseconds: number): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.API = void 0;
|
|
4
|
+
const utils_1 = require("../lib/utils");
|
|
5
|
+
class API {
|
|
6
|
+
// Mock implementation, doesn't actually send an email
|
|
7
|
+
sendEmail(to, subject, body) {
|
|
8
|
+
console.log(`Sending email to "${to}" with subject "${subject}" and body\n"${body}"`);
|
|
9
|
+
return (0, utils_1.delay)(1000);
|
|
10
|
+
}
|
|
11
|
+
getSalesData() {
|
|
12
|
+
return [
|
|
13
|
+
{ sales: 100, month: 1, year: 2020, businessUnit: "Advertising" },
|
|
14
|
+
{ sales: 200, month: 2, year: 2020, businessUnit: "Advertising" },
|
|
15
|
+
{ sales: 300, month: 3, year: 2020, businessUnit: "Advertising" },
|
|
16
|
+
{ sales: 400, month: 4, year: 2020, businessUnit: "Advertising" },
|
|
17
|
+
{ sales: 500, month: 5, year: 2020, businessUnit: "Advertising" },
|
|
18
|
+
{ sales: 600, month: 6, year: 2020, businessUnit: "Advertising" },
|
|
19
|
+
{ sales: 700, month: 7, year: 2020, businessUnit: "Advertising" },
|
|
20
|
+
{ sales: 800, month: 8, year: 2020, businessUnit: "Advertising" },
|
|
21
|
+
{ sales: 900, month: 9, year: 2020, businessUnit: "Advertising" },
|
|
22
|
+
{ sales: 1000, month: 10, year: 2020, businessUnit: "Advertising" },
|
|
23
|
+
{ sales: 1100, month: 11, year: 2020, businessUnit: "Advertising" },
|
|
24
|
+
{ sales: 1100, month: 12, year: 2020, businessUnit: "Advertising" },
|
|
25
|
+
{ sales: 1200, month: 1, year: 2020, businessUnit: "Software" },
|
|
26
|
+
{ sales: 1300, month: 2, year: 2020, businessUnit: "Software" },
|
|
27
|
+
{ sales: 1400, month: 3, year: 2020, businessUnit: "Software" },
|
|
28
|
+
{ sales: 1500, month: 4, year: 2020, businessUnit: "Software" },
|
|
29
|
+
{ sales: 1600, month: 5, year: 2020, businessUnit: "Software" },
|
|
30
|
+
{ sales: 1700, month: 6, year: 2020, businessUnit: "Software" },
|
|
31
|
+
{ sales: 1800, month: 7, year: 2020, businessUnit: "Software" },
|
|
32
|
+
{ sales: 1800, month: 8, year: 2020, businessUnit: "Software" },
|
|
33
|
+
{ sales: 1500, month: 9, year: 2020, businessUnit: "Software" },
|
|
34
|
+
{ sales: 1200, month: 10, year: 2020, businessUnit: "Software" },
|
|
35
|
+
{ sales: 1000, month: 11, year: 2020, businessUnit: "Software" },
|
|
36
|
+
{ sales: 100, month: 12, year: 2020, businessUnit: "Software" },
|
|
37
|
+
{ sales: 1200, month: 1, year: 2020, businessUnit: "Hardware" },
|
|
38
|
+
{ sales: 1300, month: 2, year: 2020, businessUnit: "Hardware" },
|
|
39
|
+
{ sales: 1400, month: 3, year: 2020, businessUnit: "Hardware" },
|
|
40
|
+
{ sales: 1500, month: 4, year: 2020, businessUnit: "Hardware" },
|
|
41
|
+
{ sales: 1600, month: 5, year: 2020, businessUnit: "Hardware" },
|
|
42
|
+
{ sales: 1700, month: 6, year: 2020, businessUnit: "Hardware" },
|
|
43
|
+
{ sales: 1800, month: 7, year: 2020, businessUnit: "Hardware" },
|
|
44
|
+
{ sales: 1800, month: 8, year: 2020, businessUnit: "Hardware" },
|
|
45
|
+
{ sales: 1500, month: 9, year: 2020, businessUnit: "Hardware" },
|
|
46
|
+
{ sales: 1200, month: 10, year: 2020, businessUnit: "Hardware" },
|
|
47
|
+
{ sales: 1000, month: 11, year: 2020, businessUnit: "Hardware" },
|
|
48
|
+
{ sales: 100, month: 12, year: 2020, businessUnit: "Hardware" },
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
;
|
|
52
|
+
print(text) {
|
|
53
|
+
console.log(text);
|
|
54
|
+
}
|
|
55
|
+
delay(milliseconds) {
|
|
56
|
+
return (0, utils_1.delay)(milliseconds);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.API = API;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ChatCompletionRequestMessage } from "openai";
|
|
2
|
+
import { QuickJSWASMModule } from "quickjs-emscripten";
|
|
3
|
+
export declare function createBasePrompt(apiFilePath: string, documentationPath: string): string;
|
|
4
|
+
export declare const generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[], createTaskPrompt: string, apiPath: string, debug?: boolean) => Promise<string>;
|
|
5
|
+
export interface AIMyAPIOptions {
|
|
6
|
+
apiObject: object;
|
|
7
|
+
apiExports: object;
|
|
8
|
+
apiGlobals?: object;
|
|
9
|
+
apiDefFilePath: string;
|
|
10
|
+
apiGlobalName?: string;
|
|
11
|
+
apiDocsPath?: string;
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface CreateWithAPIExports {
|
|
15
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[]) => Promise<string>;
|
|
16
|
+
runCode: (task: string) => Promise<void>;
|
|
17
|
+
processRequest: (userQuery: string, context?: object) => Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
export interface AIMyAPIExports {
|
|
20
|
+
createWithAPI: (options: AIMyAPIOptions) => Promise<CreateWithAPIExports>;
|
|
21
|
+
createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
|
|
22
|
+
generateTask: (queryText: string, userChatHistory: any[], createTaskPrompt: string, apiPath: string) => Promise<string>;
|
|
23
|
+
createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
|
|
24
|
+
}
|
|
25
|
+
declare const aimyapi: AIMyAPIExports;
|
|
26
|
+
export default aimyapi;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateCode = exports.createBasePrompt = void 0;
|
|
7
|
+
require('dotenv').config();
|
|
8
|
+
const openai_1 = require("openai");
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const sandbox_1 = __importDefault(require("./sandbox"));
|
|
12
|
+
const sandbox_wrappers_1 = require("./sandbox-wrappers");
|
|
13
|
+
const quickjs_emscripten_1 = require("quickjs-emscripten");
|
|
14
|
+
const configuration = new openai_1.Configuration({
|
|
15
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
16
|
+
});
|
|
17
|
+
const openai = new openai_1.OpenAIApi(configuration);
|
|
18
|
+
// function formatObject(obj: any): string {
|
|
19
|
+
// return Object.keys(obj).reduce((acc, key) => {
|
|
20
|
+
// return `${acc}${key}:\n${obj[key]}\n\n`;
|
|
21
|
+
// }, "");
|
|
22
|
+
// }
|
|
23
|
+
function createBasePrompt(apiFilePath, documentationPath) {
|
|
24
|
+
const apiText = fs_1.default.readFileSync(apiFilePath, 'utf8');
|
|
25
|
+
const documentationText = documentationPath ? fs_1.default.readFileSync(documentationPath, 'utf8') : '';
|
|
26
|
+
//console.time("Loading templates");
|
|
27
|
+
const createTaskPrompt = fs_1.default.readFileSync(path_1.default.join(__dirname, '../prompts/create-task-prompt.md'), 'utf8').replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText);
|
|
28
|
+
//console.timeEnd("Loading templates")
|
|
29
|
+
return createTaskPrompt;
|
|
30
|
+
}
|
|
31
|
+
exports.createBasePrompt = createBasePrompt;
|
|
32
|
+
// userChatHistory is not currently used but could be in the future.
|
|
33
|
+
const generateCode = async function (queryText, userChatHistory, createTaskPrompt, apiPath, debug = false) {
|
|
34
|
+
if (!queryText)
|
|
35
|
+
return;
|
|
36
|
+
let generatedCode = '';
|
|
37
|
+
const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
|
|
38
|
+
// TODO: I should switch this back to gpt3.5 turbo since it's cheaper
|
|
39
|
+
try {
|
|
40
|
+
// const task = await openai.createCompletion(
|
|
41
|
+
// {
|
|
42
|
+
// model: "text-davinci-003",
|
|
43
|
+
// prompt,
|
|
44
|
+
// temperature: 0.1,
|
|
45
|
+
// max_tokens: 1100,
|
|
46
|
+
// }
|
|
47
|
+
// );
|
|
48
|
+
const results = await openai.createChatCompletion({
|
|
49
|
+
model: "gpt-3.5-turbo",
|
|
50
|
+
messages: [
|
|
51
|
+
{
|
|
52
|
+
role: "system",
|
|
53
|
+
content: prompt,
|
|
54
|
+
},
|
|
55
|
+
...userChatHistory,
|
|
56
|
+
{
|
|
57
|
+
role: "user",
|
|
58
|
+
content: `${queryText}`,
|
|
59
|
+
name: "user"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
temperature: 0.1,
|
|
63
|
+
max_tokens: 800,
|
|
64
|
+
});
|
|
65
|
+
if (debug)
|
|
66
|
+
console.log(results.data.usage);
|
|
67
|
+
const response = results.data.choices[0].message.content;
|
|
68
|
+
if (debug)
|
|
69
|
+
console.log(response);
|
|
70
|
+
// Return only the code between ``` and ``` (usually at the end of the completion)
|
|
71
|
+
const codeStart = response.indexOf('```');
|
|
72
|
+
const codeEnd = response.lastIndexOf('```');
|
|
73
|
+
if (codeStart === -1 || codeEnd === -1 || codeStart === codeEnd)
|
|
74
|
+
return '';
|
|
75
|
+
generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
|
|
76
|
+
generatedCode = `// Query=${queryText}\n` + generatedCode.replace("./api.ts", apiPath);
|
|
77
|
+
return generatedCode;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
console.error(err);
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
exports.generateCode = generateCode;
|
|
85
|
+
let QuickJS = null;
|
|
86
|
+
;
|
|
87
|
+
async function createWithAPI(options) {
|
|
88
|
+
// extend options with defaults
|
|
89
|
+
options = {
|
|
90
|
+
apiGlobalName: "api",
|
|
91
|
+
apiGlobals: {},
|
|
92
|
+
debug: false,
|
|
93
|
+
...options
|
|
94
|
+
};
|
|
95
|
+
if (!options.apiObject || !options.apiDefFilePath) {
|
|
96
|
+
throw new Error("apiObject and apiFilePath are required");
|
|
97
|
+
}
|
|
98
|
+
const { apiObject, apiGlobalName, apiExports, apiDefFilePath, apiDocsPath, debug } = options;
|
|
99
|
+
const whitelist = Object.getOwnPropertyNames(Object.getPrototypeOf(apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_"));
|
|
100
|
+
const createTaskPrompt = createBasePrompt(apiDefFilePath, apiDocsPath);
|
|
101
|
+
return {
|
|
102
|
+
generateCode: async function (queryText, userChatHistory, currentContext = undefined) {
|
|
103
|
+
if (!queryText)
|
|
104
|
+
return '';
|
|
105
|
+
return await (0, exports.generateCode)(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug);
|
|
106
|
+
},
|
|
107
|
+
runCode: async function (generatedCode) {
|
|
108
|
+
if (!QuickJS) {
|
|
109
|
+
// Create QuickJS
|
|
110
|
+
if (debug)
|
|
111
|
+
console.log("Creating quick.js");
|
|
112
|
+
QuickJS = await (0, quickjs_emscripten_1.getQuickJS)();
|
|
113
|
+
}
|
|
114
|
+
let apiGlobals = {};
|
|
115
|
+
for (const key in options.apiGlobals) {
|
|
116
|
+
apiGlobals[key] = {
|
|
117
|
+
value: options.apiGlobals[key],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Create sandbox
|
|
121
|
+
// NOTE: not sure why I have to replace the backslash here
|
|
122
|
+
const { vm, runTask, isAsyncProcessRunning } = await (0, sandbox_1.default)(QuickJS, {
|
|
123
|
+
[apiDefFilePath.replaceAll("\\", "")]: apiExports,
|
|
124
|
+
}, {
|
|
125
|
+
...apiGlobals,
|
|
126
|
+
[apiGlobalName]: {
|
|
127
|
+
value: apiObject,
|
|
128
|
+
whitelist
|
|
129
|
+
}
|
|
130
|
+
}, options.debug);
|
|
131
|
+
try {
|
|
132
|
+
const res = await runTask(generatedCode);
|
|
133
|
+
if (!res) {
|
|
134
|
+
console.error("Task unsuccessful");
|
|
135
|
+
}
|
|
136
|
+
while (isAsyncProcessRunning()) {
|
|
137
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
138
|
+
}
|
|
139
|
+
if (debug) {
|
|
140
|
+
console.log("Completed");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
if (debug) {
|
|
145
|
+
console.error("Error running task:", err);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
149
|
+
(0, sandbox_wrappers_1.rejectOpenPromises)(vm);
|
|
150
|
+
vm.dispose();
|
|
151
|
+
},
|
|
152
|
+
processRequest: async function (userQuery, currentContext = undefined) {
|
|
153
|
+
// Create prompt
|
|
154
|
+
if (debug) {
|
|
155
|
+
console.log("Query:", userQuery);
|
|
156
|
+
}
|
|
157
|
+
// Generate Code
|
|
158
|
+
console.time("Generate Task");
|
|
159
|
+
const generatedCode = await (0, exports.generateCode)(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
|
|
160
|
+
console.timeEnd("Generate Task");
|
|
161
|
+
if (debug) {
|
|
162
|
+
console.log("Generated Code:", generatedCode);
|
|
163
|
+
}
|
|
164
|
+
console.time("Run Code");
|
|
165
|
+
await this.runCode(generatedCode);
|
|
166
|
+
console.timeEnd("Run Code");
|
|
167
|
+
return generatedCode;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const aimyapi = {
|
|
172
|
+
// Standard way of using the library
|
|
173
|
+
createWithAPI,
|
|
174
|
+
// functions for customized usage
|
|
175
|
+
createBasePrompt,
|
|
176
|
+
generateTask: exports.generateCode,
|
|
177
|
+
createSandbox: sandbox_1.default,
|
|
178
|
+
};
|
|
179
|
+
exports.default = aimyapi;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "quickjs-emscripten";
|
|
2
|
+
export declare function wrapPromise(vm: any, promise: Promise<any>, beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
3
|
+
export declare function rejectOpenPromises(vm: any): void;
|
|
4
|
+
export declare function wrap(vm: any, value: any, context: object, beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
5
|
+
export declare function wrapObject(vm: any, obj: any, beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
6
|
+
export declare function wrapObjectWhitelist(vm: any, obj: any, whitelist: string[], beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
7
|
+
export declare function wrapArray(vm: any, arr: any[], beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
8
|
+
export declare function wrapGenericFunction(vm: any, fn: Function, context: object, beginAsyncProcess: () => void, endAsyncProcess: () => void): any;
|
|
9
|
+
export declare function injectTimingFunctions(vm: any, cbAddedTimer: any, cbRemovedTimer: any, maxTimeout?: number): void;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectTimingFunctions = exports.wrapGenericFunction = exports.wrapArray = exports.wrapObjectWhitelist = exports.wrapObject = exports.wrap = exports.rejectOpenPromises = exports.wrapPromise = void 0;
|
|
4
|
+
require("quickjs-emscripten");
|
|
5
|
+
let promiseId = 0;
|
|
6
|
+
let openPromises = {};
|
|
7
|
+
function wrapPromise(vm, promise, beginAsyncProcess, endAsyncProcess) {
|
|
8
|
+
promiseId += 1;
|
|
9
|
+
const vmPromise = vm.newPromise();
|
|
10
|
+
vmPromise._promiseId = promiseId;
|
|
11
|
+
beginAsyncProcess();
|
|
12
|
+
promise.then((...args) => {
|
|
13
|
+
//console.log("Promised resolved", args);
|
|
14
|
+
endAsyncProcess();
|
|
15
|
+
const wrappedArgs = args.map((arg) => wrap(vm, arg, undefined, beginAsyncProcess, endAsyncProcess));
|
|
16
|
+
openPromises[vmPromise._promiseId] = null;
|
|
17
|
+
vmPromise.resolve(...wrappedArgs);
|
|
18
|
+
wrappedArgs.forEach((arg) => arg.dispose());
|
|
19
|
+
}).catch((...args) => {
|
|
20
|
+
//console.log("Promised rejected", args);
|
|
21
|
+
const wrappedArgs = args.map((arg) => wrap(vm, arg, undefined, beginAsyncProcess, endAsyncProcess));
|
|
22
|
+
vmPromise.reject(...wrappedArgs);
|
|
23
|
+
wrappedArgs.forEach((arg) => arg.dispose());
|
|
24
|
+
openPromises[vmPromise._promiseId] = null;
|
|
25
|
+
});
|
|
26
|
+
vmPromise.settled.then(() => {
|
|
27
|
+
endAsyncProcess();
|
|
28
|
+
vm.runtime.executePendingJobs();
|
|
29
|
+
});
|
|
30
|
+
openPromises[promiseId] = vmPromise;
|
|
31
|
+
return vmPromise.handle;
|
|
32
|
+
}
|
|
33
|
+
exports.wrapPromise = wrapPromise;
|
|
34
|
+
function rejectOpenPromises(vm) {
|
|
35
|
+
for (const [id, promise] of Object.entries(openPromises)) {
|
|
36
|
+
if (promise !== null) {
|
|
37
|
+
promise.reject(vm.newError("Shutting down"));
|
|
38
|
+
openPromises[id] = null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
vm.runtime.executePendingJobs();
|
|
42
|
+
}
|
|
43
|
+
exports.rejectOpenPromises = rejectOpenPromises;
|
|
44
|
+
function wrap(vm, value, context, beginAsyncProcess, endAsyncProcess) {
|
|
45
|
+
if (value === null) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
else if (typeof value === 'object' && typeof value.then === 'function') {
|
|
49
|
+
//console.log("Wrapped promise");
|
|
50
|
+
return wrapPromise(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
51
|
+
}
|
|
52
|
+
else if (typeof value === "function") {
|
|
53
|
+
//console.log("Wrapped function")
|
|
54
|
+
return wrapGenericFunction(vm, value, context, beginAsyncProcess, endAsyncProcess);
|
|
55
|
+
}
|
|
56
|
+
else if (Array.isArray(value)) {
|
|
57
|
+
//console.log("Wrapped array")
|
|
58
|
+
return wrapArray(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
59
|
+
}
|
|
60
|
+
else if (value === null) {
|
|
61
|
+
//console.log("Wrapped null")
|
|
62
|
+
return vm.null;
|
|
63
|
+
}
|
|
64
|
+
else if (typeof value === "object") {
|
|
65
|
+
//console.log("Wrapped object")
|
|
66
|
+
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
67
|
+
}
|
|
68
|
+
else if (typeof value === "string") {
|
|
69
|
+
//console.log("Wrapped string")
|
|
70
|
+
return vm.newString(value);
|
|
71
|
+
}
|
|
72
|
+
else if (typeof value === "number") {
|
|
73
|
+
//console.log("Wrapped number")
|
|
74
|
+
return vm.newNumber(value);
|
|
75
|
+
}
|
|
76
|
+
else if (typeof value === "bigint") {
|
|
77
|
+
//console.log("Wrapped bigint")
|
|
78
|
+
return vm.newBigInt(value);
|
|
79
|
+
}
|
|
80
|
+
else if (typeof value === "boolean") {
|
|
81
|
+
// since there is no newBoolean, we have to do this
|
|
82
|
+
return vm.evalCode(value ? "true" : "false").value;
|
|
83
|
+
}
|
|
84
|
+
else if (typeof value === "undefined") {
|
|
85
|
+
return vm.undefined;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.wrap = wrap;
|
|
92
|
+
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
93
|
+
const vmObject = vm.newObject();
|
|
94
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
95
|
+
//console.log("wrapping", key, value)
|
|
96
|
+
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
97
|
+
if (wrappedValue !== null) {
|
|
98
|
+
vm.setProp(vmObject, key, wrappedValue);
|
|
99
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
100
|
+
wrappedValue.dispose();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return vmObject;
|
|
105
|
+
}
|
|
106
|
+
exports.wrapObject = wrapObject;
|
|
107
|
+
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess) {
|
|
108
|
+
const vmObject = vm.newObject();
|
|
109
|
+
whitelist.forEach((key) => {
|
|
110
|
+
const value = obj[key];
|
|
111
|
+
//console.log("wrapping", key, value)
|
|
112
|
+
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
113
|
+
if (wrappedValue !== null) {
|
|
114
|
+
vm.setProp(vmObject, key, wrappedValue);
|
|
115
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
116
|
+
wrappedValue.dispose();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
return vmObject;
|
|
121
|
+
}
|
|
122
|
+
exports.wrapObjectWhitelist = wrapObjectWhitelist;
|
|
123
|
+
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
124
|
+
const vmArray = vm.newArray();
|
|
125
|
+
for (let i = 0; i < arr.length; i++) {
|
|
126
|
+
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess);
|
|
127
|
+
vm.setProp(vmArray, i, wrappedValue);
|
|
128
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null) {
|
|
129
|
+
wrappedValue.dispose();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return vmArray;
|
|
133
|
+
}
|
|
134
|
+
exports.wrapArray = wrapArray;
|
|
135
|
+
function wrapGenericFunction(vm, fn, context = undefined, beginAsyncProcess, endAsyncProcess) {
|
|
136
|
+
const vmFn = vm.newFunction(fn.name, (...args) => {
|
|
137
|
+
const unwrappedArgs = args.map(vm.dump);
|
|
138
|
+
//console.log("Wrapped function called", fn.name, unwrappedArgs )
|
|
139
|
+
try {
|
|
140
|
+
const result = fn.call(context, ...unwrappedArgs);
|
|
141
|
+
//console.log("result", result);
|
|
142
|
+
const wrappedResult = wrap(vm, result, undefined, beginAsyncProcess, endAsyncProcess);
|
|
143
|
+
return wrappedResult;
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
console.log("Error", e);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return vmFn;
|
|
150
|
+
}
|
|
151
|
+
exports.wrapGenericFunction = wrapGenericFunction;
|
|
152
|
+
function injectTimingFunctions(vm, cbAddedTimer, cbRemovedTimer, maxTimeout = 600000) {
|
|
153
|
+
// Should we impose a limit on how long things can run for?
|
|
154
|
+
const timeoutFunctionHandles = {};
|
|
155
|
+
const _setTimeout = vm.newFunction("setTimeout", (vmFnHandle, timeoutHandle) => {
|
|
156
|
+
// Make a copy because otherwise vmFnHandle does not live long enough to call after the timeout
|
|
157
|
+
const vmFnHandleCopy = vmFnHandle.dup();
|
|
158
|
+
let timeout = vm.dump(timeoutHandle);
|
|
159
|
+
// cap timeout at max timeout
|
|
160
|
+
if (timeout > maxTimeout) {
|
|
161
|
+
timeout = maxTimeout;
|
|
162
|
+
}
|
|
163
|
+
// console.log("Sandbox calling timeout for: " + timeout);
|
|
164
|
+
cbAddedTimer();
|
|
165
|
+
const timeoutID = setTimeout(() => {
|
|
166
|
+
timeoutFunctionHandles[timeoutID.toString()] = null;
|
|
167
|
+
// callFunction(vmFnHandleCopy) will call the vm function
|
|
168
|
+
// in the context of the vm
|
|
169
|
+
// we pass vm.undefined because we need to pass something for the "this" argument
|
|
170
|
+
//console.log("Sandbox called timeout function")
|
|
171
|
+
cbRemovedTimer();
|
|
172
|
+
vm.callFunction(vmFnHandleCopy, vm.undefined);
|
|
173
|
+
vmFnHandleCopy.dispose();
|
|
174
|
+
vm.runtime.executePendingJobs();
|
|
175
|
+
}, timeout);
|
|
176
|
+
timeoutFunctionHandles[timeoutID.toString()] = vmFnHandleCopy;
|
|
177
|
+
return vm.newNumber(timeoutID);
|
|
178
|
+
});
|
|
179
|
+
vm.setProp(vm.global, "setTimeout", _setTimeout);
|
|
180
|
+
_setTimeout.dispose();
|
|
181
|
+
const intervalFunctionHandles = {};
|
|
182
|
+
const _setInterval = vm.newFunction("setInterval", (vmFnHandle, timeoutHandle) => {
|
|
183
|
+
// Make a copy because otherwise vmFnHandle does not live long enough to call after the timeout
|
|
184
|
+
const vmFnHandleCopy = vmFnHandle.dup();
|
|
185
|
+
let timeout = vm.dump(timeoutHandle);
|
|
186
|
+
// cap timeout at max timeout
|
|
187
|
+
if (timeout > maxTimeout) {
|
|
188
|
+
timeout = maxTimeout;
|
|
189
|
+
}
|
|
190
|
+
//console.log("Sandbox calling interval for: " + timeout);
|
|
191
|
+
const maxRepetitions = 99;
|
|
192
|
+
let repetitions = 0;
|
|
193
|
+
cbAddedTimer();
|
|
194
|
+
const intervalId = setInterval(() => {
|
|
195
|
+
repetitions += 1;
|
|
196
|
+
intervalFunctionHandles[intervalId.toString()] = null;
|
|
197
|
+
// callFunction(vmFnHandleCopy) will call the vm function
|
|
198
|
+
// in the context of the vm
|
|
199
|
+
// we pass vm.undefined because we need to pass something for the "this" argument
|
|
200
|
+
vm.callFunction(vmFnHandleCopy, vm.undefined);
|
|
201
|
+
vm.runtime.executePendingJobs();
|
|
202
|
+
if (repetitions > maxRepetitions) {
|
|
203
|
+
console.log("Sandbox interval exceeded max repetitions");
|
|
204
|
+
clearInterval(intervalId);
|
|
205
|
+
cbRemovedTimer();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}, timeout);
|
|
209
|
+
intervalFunctionHandles[intervalId.toString()] = vmFnHandleCopy;
|
|
210
|
+
return vm.newNumber(intervalId);
|
|
211
|
+
});
|
|
212
|
+
vm.setProp(vm.global, "setInterval", _setInterval);
|
|
213
|
+
_setInterval.dispose();
|
|
214
|
+
const _clearTimeout = vm.newFunction("clearTimeout", (timeoutIdHandle) => {
|
|
215
|
+
const timeoutId = vm.dump(timeoutIdHandle);
|
|
216
|
+
const timeoutHandle = timeoutFunctionHandles[timeoutId.toString()];
|
|
217
|
+
if (timeoutHandle) {
|
|
218
|
+
cbRemovedTimer();
|
|
219
|
+
timeoutHandle.dispose();
|
|
220
|
+
clearTimeout(timeoutId);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
vm.setProp(vm.global, "clearTimeout", _clearTimeout);
|
|
224
|
+
_clearTimeout.dispose();
|
|
225
|
+
const _clearInterval = vm.newFunction("clearInterval", (intervalIdHandle) => {
|
|
226
|
+
const intervalId = vm.dump(intervalIdHandle);
|
|
227
|
+
const intervalHandle = intervalFunctionHandles[intervalId.toString()];
|
|
228
|
+
if (intervalId) {
|
|
229
|
+
cbRemovedTimer();
|
|
230
|
+
intervalHandle.dispose();
|
|
231
|
+
clearInterval(intervalId);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
vm.setProp(vm.global, "clearInterval", _clearInterval);
|
|
235
|
+
_clearInterval.dispose();
|
|
236
|
+
}
|
|
237
|
+
exports.injectTimingFunctions = injectTimingFunctions;
|