aimyapi 0.1.11 → 0.1.14
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 +16 -4
- package/dist/index.cjs +492 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.d.ts +14 -11
- package/dist/index.js +480 -163
- package/dist/index.mjs +468 -0
- package/example/example1.ts +1 -1
- package/example/example2.ts +1 -1
- package/example/example3.ts +3 -3
- package/example/ordering_api_impl.ts +5 -5
- package/example/sales_api.md +2 -0
- package/example/sales_api.ts +1 -1
- package/example/sales_api_impl.ts +1 -1
- package/package.json +19 -7
- package/prompts/create-task-prompt.md +1 -1
- package/{lib → src}/index.ts +21 -21
- package/tsconfig.json +2 -2
- /package/{lib → src}/sandbox-wrappers.ts +0 -0
- /package/{lib → src}/sandbox.ts +0 -0
- /package/{lib → src}/utils.ts +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# AI My API
|
|
2
2
|
|
|
3
|
-
Build AI assistants that use your API's and respond to natural language queries by writing small programs that are executed in a [QuickJS](https://github.com/justjake/quickjs-emscripten) sandbox.
|
|
4
|
-
|
|
5
|
-
for example, being able to sort or filter your data in new ways, email or text yourself results, or combine the results of different operations and API's.
|
|
3
|
+
Build AI assistants that use your API's and respond to natural language queries by writing small programs that are executed in a [QuickJS](https://github.com/justjake/quickjs-emscripten) sandbox. Similar to chatGPT Code Interpreter but running on your servers and calling your own API.
|
|
4
|
+
|
|
5
|
+
AIMyAPI writes the glue between your various API functions unlocking new functionality without having to write any code. With the right building blocks, AIMyAPI can even invent new functionality you didn't originally plan for - for example, being able to sort or filter your data in new ways, email or text yourself results, or combine the results of different operations and API's.
|
|
6
6
|
|
|
7
7
|
Uses the OpenAI API and requires an API key.
|
|
8
8
|
|
|
@@ -45,7 +45,7 @@ declare global {
|
|
|
45
45
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Implement it:
|
|
48
|
+
Implement it (`sales_api_impl.ts`):
|
|
49
49
|
```
|
|
50
50
|
export class API implements APIInterface {
|
|
51
51
|
|
|
@@ -53,6 +53,18 @@ export class API implements APIInterface {
|
|
|
53
53
|
...
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
Document it (`sales_api.md`):
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Examples of how you should respond:
|
|
60
|
+
|
|
61
|
+
user: How are you today?
|
|
62
|
+
|
|
63
|
+
assistant:
|
|
64
|
+
|
|
65
|
+
api.print("I'm great, thanks for asking!");
|
|
66
|
+
```
|
|
67
|
+
|
|
56
68
|
Instantiate your api and AIMyAPI. AIMyAPI will wrap your API so that it can be called from within the QuickJS sandbox.
|
|
57
69
|
|
|
58
70
|
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var module$1 = require('module');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var openai$1 = require('openai');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var quickjsEmscripten = require('quickjs-emscripten');
|
|
8
|
+
var ts = require('typescript');
|
|
9
|
+
|
|
10
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
11
|
+
function _interopNamespaceDefault(e) {
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var ts__namespace = /*#__PURE__*/_interopNamespaceDefault(ts);
|
|
29
|
+
|
|
30
|
+
var require$1 = (
|
|
31
|
+
false
|
|
32
|
+
? /* @__PURE__ */ module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))
|
|
33
|
+
: require
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
let promiseId = 0;
|
|
37
|
+
let openPromises = {};
|
|
38
|
+
function wrapPromise(vm, promise, beginAsyncProcess, endAsyncProcess) {
|
|
39
|
+
promiseId += 1;
|
|
40
|
+
const vmPromise = vm.newPromise();
|
|
41
|
+
vmPromise._promiseId = promiseId;
|
|
42
|
+
beginAsyncProcess();
|
|
43
|
+
promise.then((...args) => {
|
|
44
|
+
endAsyncProcess();
|
|
45
|
+
const wrappedArgs = args.map((arg) => wrap(vm, arg, void 0, beginAsyncProcess, endAsyncProcess));
|
|
46
|
+
openPromises[vmPromise._promiseId] = null;
|
|
47
|
+
vmPromise.resolve(...wrappedArgs);
|
|
48
|
+
wrappedArgs.forEach((arg) => arg.dispose());
|
|
49
|
+
}).catch((...args) => {
|
|
50
|
+
const wrappedArgs = args.map((arg) => wrap(vm, arg, void 0, beginAsyncProcess, endAsyncProcess));
|
|
51
|
+
vmPromise.reject(...wrappedArgs);
|
|
52
|
+
wrappedArgs.forEach((arg) => arg.dispose());
|
|
53
|
+
openPromises[vmPromise._promiseId] = null;
|
|
54
|
+
});
|
|
55
|
+
vmPromise.settled.then(() => {
|
|
56
|
+
endAsyncProcess();
|
|
57
|
+
vm.runtime.executePendingJobs();
|
|
58
|
+
});
|
|
59
|
+
openPromises[promiseId] = vmPromise;
|
|
60
|
+
return vmPromise.handle;
|
|
61
|
+
}
|
|
62
|
+
function rejectOpenPromises(vm) {
|
|
63
|
+
for (const [id, promise] of Object.entries(openPromises)) {
|
|
64
|
+
if (promise !== null) {
|
|
65
|
+
promise.reject(vm.newError("Shutting down"));
|
|
66
|
+
openPromises[id] = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
vm.runtime.executePendingJobs();
|
|
70
|
+
}
|
|
71
|
+
function wrap(vm, value, context, beginAsyncProcess, endAsyncProcess) {
|
|
72
|
+
if (value === null) {
|
|
73
|
+
return null;
|
|
74
|
+
} else if (typeof value === "object" && typeof value.then === "function") {
|
|
75
|
+
return wrapPromise(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
76
|
+
} else if (typeof value === "function") {
|
|
77
|
+
return wrapGenericFunction(vm, value, context, beginAsyncProcess, endAsyncProcess);
|
|
78
|
+
} else if (Array.isArray(value)) {
|
|
79
|
+
return wrapArray(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
80
|
+
} else if (value === null) {
|
|
81
|
+
return vm.null;
|
|
82
|
+
} else if (typeof value === "object") {
|
|
83
|
+
return wrapObject(vm, value, beginAsyncProcess, endAsyncProcess);
|
|
84
|
+
} else if (typeof value === "string") {
|
|
85
|
+
return vm.newString(value);
|
|
86
|
+
} else if (typeof value === "number") {
|
|
87
|
+
return vm.newNumber(value);
|
|
88
|
+
} else if (typeof value === "bigint") {
|
|
89
|
+
return vm.newBigInt(value);
|
|
90
|
+
} else if (typeof value === "boolean") {
|
|
91
|
+
return vm.evalCode(value ? "true" : "false").value;
|
|
92
|
+
} else if (typeof value === "undefined") {
|
|
93
|
+
return vm.undefined;
|
|
94
|
+
} else {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function wrapObject(vm, obj, beginAsyncProcess, endAsyncProcess) {
|
|
99
|
+
const vmObject = vm.newObject();
|
|
100
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
101
|
+
let wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
102
|
+
if (wrappedValue !== null) {
|
|
103
|
+
vm.setProp(vmObject, key, wrappedValue);
|
|
104
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
105
|
+
wrappedValue.dispose();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return vmObject;
|
|
110
|
+
}
|
|
111
|
+
function wrapObjectWhitelist(vm, obj, whitelist, beginAsyncProcess, endAsyncProcess) {
|
|
112
|
+
const vmObject = vm.newObject();
|
|
113
|
+
whitelist.forEach((key) => {
|
|
114
|
+
const value = obj[key];
|
|
115
|
+
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess);
|
|
116
|
+
if (wrappedValue !== null) {
|
|
117
|
+
vm.setProp(vmObject, key, wrappedValue);
|
|
118
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null && wrappedValue.dispose) {
|
|
119
|
+
wrappedValue.dispose();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return vmObject;
|
|
124
|
+
}
|
|
125
|
+
function wrapArray(vm, arr, beginAsyncProcess, endAsyncProcess) {
|
|
126
|
+
const vmArray = vm.newArray();
|
|
127
|
+
for (let i = 0; i < arr.length; i++) {
|
|
128
|
+
let wrappedValue = wrap(vm, arr[i], arr, beginAsyncProcess, endAsyncProcess);
|
|
129
|
+
vm.setProp(vmArray, i, wrappedValue);
|
|
130
|
+
if (wrappedValue != vm.undefined && wrappedValue != vm.null) {
|
|
131
|
+
wrappedValue.dispose();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return vmArray;
|
|
135
|
+
}
|
|
136
|
+
function wrapGenericFunction(vm, fn, context = void 0, beginAsyncProcess, endAsyncProcess) {
|
|
137
|
+
const vmFn = vm.newFunction(fn.name, (...args) => {
|
|
138
|
+
const unwrappedArgs = args.map(vm.dump);
|
|
139
|
+
try {
|
|
140
|
+
const result = fn.call(context, ...unwrappedArgs);
|
|
141
|
+
const wrappedResult = wrap(vm, result, void 0, beginAsyncProcess, endAsyncProcess);
|
|
142
|
+
return wrappedResult;
|
|
143
|
+
} catch (e) {
|
|
144
|
+
console.log("Error", e);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
return vmFn;
|
|
148
|
+
}
|
|
149
|
+
function injectTimingFunctions(vm, cbAddedTimer, cbRemovedTimer, maxTimeout = 6e5) {
|
|
150
|
+
const timeoutFunctionHandles = {};
|
|
151
|
+
const _setTimeout = vm.newFunction("setTimeout", (vmFnHandle, timeoutHandle) => {
|
|
152
|
+
const vmFnHandleCopy = vmFnHandle.dup();
|
|
153
|
+
let timeout = vm.dump(timeoutHandle);
|
|
154
|
+
if (timeout > maxTimeout) {
|
|
155
|
+
timeout = maxTimeout;
|
|
156
|
+
}
|
|
157
|
+
cbAddedTimer();
|
|
158
|
+
const timeoutID = setTimeout(() => {
|
|
159
|
+
timeoutFunctionHandles[timeoutID.toString()] = null;
|
|
160
|
+
cbRemovedTimer();
|
|
161
|
+
vm.callFunction(vmFnHandleCopy, vm.undefined);
|
|
162
|
+
vmFnHandleCopy.dispose();
|
|
163
|
+
vm.runtime.executePendingJobs();
|
|
164
|
+
}, timeout);
|
|
165
|
+
timeoutFunctionHandles[timeoutID.toString()] = vmFnHandleCopy;
|
|
166
|
+
return vm.newNumber(timeoutID);
|
|
167
|
+
});
|
|
168
|
+
vm.setProp(vm.global, "setTimeout", _setTimeout);
|
|
169
|
+
_setTimeout.dispose();
|
|
170
|
+
const intervalFunctionHandles = {};
|
|
171
|
+
const _setInterval = vm.newFunction("setInterval", (vmFnHandle, timeoutHandle) => {
|
|
172
|
+
const vmFnHandleCopy = vmFnHandle.dup();
|
|
173
|
+
let timeout = vm.dump(timeoutHandle);
|
|
174
|
+
if (timeout > maxTimeout) {
|
|
175
|
+
timeout = maxTimeout;
|
|
176
|
+
}
|
|
177
|
+
const maxRepetitions = 99;
|
|
178
|
+
let repetitions = 0;
|
|
179
|
+
cbAddedTimer();
|
|
180
|
+
const intervalId = setInterval(() => {
|
|
181
|
+
repetitions += 1;
|
|
182
|
+
intervalFunctionHandles[intervalId.toString()] = null;
|
|
183
|
+
vm.callFunction(vmFnHandleCopy, vm.undefined);
|
|
184
|
+
vm.runtime.executePendingJobs();
|
|
185
|
+
if (repetitions > maxRepetitions) {
|
|
186
|
+
console.log("Sandbox interval exceeded max repetitions");
|
|
187
|
+
clearInterval(intervalId);
|
|
188
|
+
cbRemovedTimer();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
}, timeout);
|
|
192
|
+
intervalFunctionHandles[intervalId.toString()] = vmFnHandleCopy;
|
|
193
|
+
return vm.newNumber(intervalId);
|
|
194
|
+
});
|
|
195
|
+
vm.setProp(vm.global, "setInterval", _setInterval);
|
|
196
|
+
_setInterval.dispose();
|
|
197
|
+
const _clearTimeout = vm.newFunction("clearTimeout", (timeoutIdHandle) => {
|
|
198
|
+
const timeoutId = vm.dump(timeoutIdHandle);
|
|
199
|
+
const timeoutHandle = timeoutFunctionHandles[timeoutId.toString()];
|
|
200
|
+
if (timeoutHandle) {
|
|
201
|
+
cbRemovedTimer();
|
|
202
|
+
timeoutHandle.dispose();
|
|
203
|
+
clearTimeout(timeoutId);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
vm.setProp(vm.global, "clearTimeout", _clearTimeout);
|
|
207
|
+
_clearTimeout.dispose();
|
|
208
|
+
const _clearInterval = vm.newFunction("clearInterval", (intervalIdHandle) => {
|
|
209
|
+
const intervalId = vm.dump(intervalIdHandle);
|
|
210
|
+
const intervalHandle = intervalFunctionHandles[intervalId.toString()];
|
|
211
|
+
if (intervalId) {
|
|
212
|
+
cbRemovedTimer();
|
|
213
|
+
intervalHandle.dispose();
|
|
214
|
+
clearInterval(intervalId);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
vm.setProp(vm.global, "clearInterval", _clearInterval);
|
|
218
|
+
_clearInterval.dispose();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function tsCompile(source, options = null) {
|
|
222
|
+
if (null === options) {
|
|
223
|
+
options = {
|
|
224
|
+
compilerOptions: {
|
|
225
|
+
target: ts__namespace.ScriptTarget.ES2020,
|
|
226
|
+
module: ts__namespace.ModuleKind.None
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return ts__namespace.transpileModule(source, options).outputText;
|
|
231
|
+
}
|
|
232
|
+
async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug = false) {
|
|
233
|
+
const vm = QuickJS.newContext();
|
|
234
|
+
let errorState = false;
|
|
235
|
+
let lastError = "";
|
|
236
|
+
let asyncProcessesRunning = 0;
|
|
237
|
+
let beginAsyncProcess = () => {
|
|
238
|
+
asyncProcessesRunning++;
|
|
239
|
+
};
|
|
240
|
+
let endAsyncProcess = () => {
|
|
241
|
+
if (asyncProcessesRunning > 0) {
|
|
242
|
+
asyncProcessesRunning--;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
let isAsyncProcessRunning = () => {
|
|
246
|
+
return asyncProcessesRunning > 0;
|
|
247
|
+
};
|
|
248
|
+
const logHandle = vm.newFunction("log", (...args) => {
|
|
249
|
+
const nativeArgs = args.map(vm.dump);
|
|
250
|
+
console.log("QuickJS Log:", ...nativeArgs);
|
|
251
|
+
});
|
|
252
|
+
const consoleHandle = vm.newObject();
|
|
253
|
+
const exportsHandle = vm.newObject();
|
|
254
|
+
const errorHandle = vm.newFunction("error", (...args) => {
|
|
255
|
+
try {
|
|
256
|
+
const nativeArgs = args.map(vm.dump);
|
|
257
|
+
console.log("QuickJS console.error:", ...nativeArgs);
|
|
258
|
+
lastError = JSON.stringify(nativeArgs);
|
|
259
|
+
errorState = true;
|
|
260
|
+
} catch (e) {
|
|
261
|
+
console.log("Error in error:", e);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
const globalNames = Object.getOwnPropertyNames(globals);
|
|
265
|
+
for (let i = 0; i < globalNames.length; i++) {
|
|
266
|
+
const globalOption = globals[globalNames[i]];
|
|
267
|
+
const globalObj = globalOption.whitelist ? wrapObjectWhitelist(
|
|
268
|
+
vm,
|
|
269
|
+
globalOption.value,
|
|
270
|
+
globalOption.whitelist,
|
|
271
|
+
beginAsyncProcess,
|
|
272
|
+
endAsyncProcess
|
|
273
|
+
) : wrap(vm, globalOption.value, globalOption, beginAsyncProcess, endAsyncProcess);
|
|
274
|
+
vm.setProp(vm.global, globalNames[i], globalObj);
|
|
275
|
+
globalObj.dispose();
|
|
276
|
+
}
|
|
277
|
+
injectTimingFunctions(vm, beginAsyncProcess, endAsyncProcess);
|
|
278
|
+
const requireHandle = vm.newFunction("require", (...args) => {
|
|
279
|
+
const nativeArgs = args.map(vm.dump);
|
|
280
|
+
if (requireLookup[nativeArgs[0]]) {
|
|
281
|
+
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess);
|
|
282
|
+
return returnObj;
|
|
283
|
+
} else {
|
|
284
|
+
return vm.undefined;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
vm.setProp(consoleHandle, "log", logHandle);
|
|
288
|
+
vm.setProp(consoleHandle, "error", errorHandle);
|
|
289
|
+
vm.setProp(vm.global, "require", requireHandle);
|
|
290
|
+
vm.setProp(vm.global, "console", consoleHandle);
|
|
291
|
+
vm.setProp(vm.global, "exports", exportsHandle);
|
|
292
|
+
consoleHandle.dispose();
|
|
293
|
+
logHandle.dispose();
|
|
294
|
+
exportsHandle.dispose();
|
|
295
|
+
errorHandle.dispose();
|
|
296
|
+
requireHandle.dispose();
|
|
297
|
+
return {
|
|
298
|
+
vm,
|
|
299
|
+
getLastError: () => {
|
|
300
|
+
return lastError;
|
|
301
|
+
},
|
|
302
|
+
isAsyncProcessRunning,
|
|
303
|
+
runTask: (task) => {
|
|
304
|
+
try {
|
|
305
|
+
const compiled = tsCompile(task);
|
|
306
|
+
if (!compiled || compiled.length === 0) {
|
|
307
|
+
console.error("Could not compile", task);
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
errorState = false;
|
|
311
|
+
const result = vm.evalCode(compiled);
|
|
312
|
+
if (result.error) {
|
|
313
|
+
const lines = compiled.split("\n");
|
|
314
|
+
for (let i = 0; i < lines.length; i++) {
|
|
315
|
+
console.log(`${i + 1}: ${lines[i]}`);
|
|
316
|
+
}
|
|
317
|
+
console.log("Execution failed:", vm.dump(result.error));
|
|
318
|
+
result.error.dispose();
|
|
319
|
+
return false;
|
|
320
|
+
} else {
|
|
321
|
+
result.value.dispose();
|
|
322
|
+
if (errorState) {
|
|
323
|
+
const lines = compiled.split("\n");
|
|
324
|
+
for (let i = 0; i < lines.length; i++) {
|
|
325
|
+
console.log(`${i + 1}: ${lines[i]}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return !errorState;
|
|
329
|
+
}
|
|
330
|
+
} catch (e) {
|
|
331
|
+
console.log(e);
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
require$1("dotenv").config();
|
|
339
|
+
const openai = new openai$1.OpenAI({
|
|
340
|
+
apiKey: process.env.OPENAI_API_KEY
|
|
341
|
+
// This is also the default, can be omitted
|
|
342
|
+
});
|
|
343
|
+
function createBasePrompt(apiFilePath, documentationPath) {
|
|
344
|
+
const apiText = fs.readFileSync(apiFilePath, "utf8");
|
|
345
|
+
const documentationText = documentationPath ? fs.readFileSync(documentationPath, "utf8") : "";
|
|
346
|
+
const createTaskPrompt = fs.readFileSync(path.join(__dirname, "../prompts/create-task-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText);
|
|
347
|
+
return createTaskPrompt;
|
|
348
|
+
}
|
|
349
|
+
const generateCode = async function(queryText, userChatHistory, createTaskPrompt, apiPath, debug = false, model = "gpt-4o") {
|
|
350
|
+
if (!queryText)
|
|
351
|
+
return { code: "", loggableCode: "" };
|
|
352
|
+
let generatedCode = "";
|
|
353
|
+
const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
|
|
354
|
+
const messages = [
|
|
355
|
+
{
|
|
356
|
+
role: "system",
|
|
357
|
+
content: prompt
|
|
358
|
+
},
|
|
359
|
+
...userChatHistory,
|
|
360
|
+
{
|
|
361
|
+
role: "user",
|
|
362
|
+
content: `${queryText}.
|
|
363
|
+
Respond only with code enclosed in \`\`\`.`,
|
|
364
|
+
name: "user"
|
|
365
|
+
}
|
|
366
|
+
];
|
|
367
|
+
try {
|
|
368
|
+
const results = await openai.chat.completions.create(
|
|
369
|
+
{
|
|
370
|
+
model,
|
|
371
|
+
messages,
|
|
372
|
+
temperature: 0,
|
|
373
|
+
max_tokens: 700
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
if (debug)
|
|
377
|
+
console.log(results.usage);
|
|
378
|
+
const response = results.choices[0].message.content;
|
|
379
|
+
if (debug)
|
|
380
|
+
console.log(response);
|
|
381
|
+
const codeStart = response.indexOf("```");
|
|
382
|
+
const codeEnd = response.lastIndexOf("```");
|
|
383
|
+
if (codeStart === -1 || codeEnd === -1 || codeStart === codeEnd) {
|
|
384
|
+
return { code: "", loggableCode: "", rawResponse: response };
|
|
385
|
+
}
|
|
386
|
+
generatedCode = response.substring(codeStart + 3, codeEnd).replace("typescript", "");
|
|
387
|
+
const codeHeader = `import * as ApiDefs from '${apiPath}'
|
|
388
|
+
(async() {
|
|
389
|
+
try {`;
|
|
390
|
+
const codeFooter = `
|
|
391
|
+
} catch(err) {
|
|
392
|
+
console.error(err);
|
|
393
|
+
}
|
|
394
|
+
})();`;
|
|
395
|
+
return { code: codeHeader + generatedCode + codeFooter, loggableCode: generatedCode };
|
|
396
|
+
} catch (err) {
|
|
397
|
+
console.error(err);
|
|
398
|
+
return { code: "", loggableCode: "" };
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
let QuickJS = null;
|
|
402
|
+
async function createWithAPI(options) {
|
|
403
|
+
options = {
|
|
404
|
+
apiGlobalName: "api",
|
|
405
|
+
apiGlobals: {},
|
|
406
|
+
apiWhitelist: Object.getOwnPropertyNames(Object.getPrototypeOf(options.apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_")),
|
|
407
|
+
debug: false,
|
|
408
|
+
model: "gpt-4o",
|
|
409
|
+
...options
|
|
410
|
+
};
|
|
411
|
+
if (!options.apiObject || !options.apiDefFilePath) {
|
|
412
|
+
throw new Error("apiObject and apiFilePath are required");
|
|
413
|
+
}
|
|
414
|
+
const { apiObject, apiWhitelist, apiGlobalName, apiExports, apiDefFilePath, apiDocsPath, debug, model } = options;
|
|
415
|
+
const createTaskPrompt = createBasePrompt(apiDefFilePath, apiDocsPath);
|
|
416
|
+
return {
|
|
417
|
+
options,
|
|
418
|
+
generateCode: async function(queryText, userChatHistory, currentContext = void 0) {
|
|
419
|
+
if (!queryText)
|
|
420
|
+
return { code: "", loggableCode: "" };
|
|
421
|
+
return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug, model);
|
|
422
|
+
},
|
|
423
|
+
runCode: async function(generatedCode) {
|
|
424
|
+
if (!QuickJS) {
|
|
425
|
+
if (debug)
|
|
426
|
+
console.log("Creating quick.js");
|
|
427
|
+
QuickJS = await quickjsEmscripten.getQuickJS();
|
|
428
|
+
}
|
|
429
|
+
let apiGlobals = {};
|
|
430
|
+
for (const key in options.apiGlobals) {
|
|
431
|
+
apiGlobals[key] = {
|
|
432
|
+
value: options.apiGlobals[key]
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
const { vm, runTask, isAsyncProcessRunning } = await createSandbox(QuickJS, {
|
|
436
|
+
[apiDefFilePath.replaceAll("\\", "")]: apiExports
|
|
437
|
+
}, {
|
|
438
|
+
...apiGlobals,
|
|
439
|
+
[apiGlobalName]: {
|
|
440
|
+
value: apiObject,
|
|
441
|
+
whitelist: apiWhitelist
|
|
442
|
+
}
|
|
443
|
+
}, options.debug);
|
|
444
|
+
try {
|
|
445
|
+
if (debug) {
|
|
446
|
+
console.log("Running Code:\n", generatedCode);
|
|
447
|
+
}
|
|
448
|
+
const res = await runTask(generatedCode);
|
|
449
|
+
if (!res) {
|
|
450
|
+
console.error("Task unsuccessful");
|
|
451
|
+
}
|
|
452
|
+
while (isAsyncProcessRunning()) {
|
|
453
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
454
|
+
}
|
|
455
|
+
if (debug) {
|
|
456
|
+
console.log("Completed");
|
|
457
|
+
}
|
|
458
|
+
} catch (err) {
|
|
459
|
+
if (debug) {
|
|
460
|
+
console.error("Error running task:", err);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
464
|
+
rejectOpenPromises(vm);
|
|
465
|
+
vm.dispose();
|
|
466
|
+
},
|
|
467
|
+
processRequest: async function(userQuery, currentContext = void 0) {
|
|
468
|
+
if (debug) {
|
|
469
|
+
console.log("Query:", userQuery);
|
|
470
|
+
}
|
|
471
|
+
console.time("Generate Task");
|
|
472
|
+
const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
|
|
473
|
+
console.timeEnd("Generate Task");
|
|
474
|
+
console.time("Run Code");
|
|
475
|
+
await this.runCode(generatedCode.code);
|
|
476
|
+
console.timeEnd("Run Code");
|
|
477
|
+
return generatedCode;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
const aimyapi = {
|
|
482
|
+
// Standard way of using the library
|
|
483
|
+
createWithAPI,
|
|
484
|
+
// functions for customized usage
|
|
485
|
+
createBasePrompt,
|
|
486
|
+
generateCode,
|
|
487
|
+
createSandbox
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
exports.aimyapi = aimyapi;
|
|
491
|
+
exports.createBasePrompt = createBasePrompt;
|
|
492
|
+
exports.generateCode = generateCode;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
|
|
2
|
+
import { QuickJSWASMModule } from 'quickjs-emscripten';
|
|
3
|
+
|
|
4
|
+
declare function createBasePrompt(apiFilePath: string, documentationPath: string): string;
|
|
5
|
+
interface GenerateCodeResult {
|
|
6
|
+
code: string;
|
|
7
|
+
loggableCode: string;
|
|
8
|
+
rawResponse?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
|
|
11
|
+
interface AIMyAPIOptions {
|
|
12
|
+
apiObject: object;
|
|
13
|
+
apiExports: object;
|
|
14
|
+
apiWhitelist?: string[];
|
|
15
|
+
apiGlobals?: object;
|
|
16
|
+
apiDefFilePath: string;
|
|
17
|
+
apiGlobalName?: string;
|
|
18
|
+
apiDocsPath?: string;
|
|
19
|
+
debug?: boolean;
|
|
20
|
+
model?: string;
|
|
21
|
+
}
|
|
22
|
+
interface AIMyAPIInstance {
|
|
23
|
+
options: AIMyAPIOptions;
|
|
24
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[]) => Promise<GenerateCodeResult>;
|
|
25
|
+
runCode: (task: string) => Promise<void>;
|
|
26
|
+
processRequest: (userQuery: string, context?: object) => Promise<GenerateCodeResult>;
|
|
27
|
+
}
|
|
28
|
+
interface AIMyAPIModuleExports {
|
|
29
|
+
createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
|
|
30
|
+
createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
|
|
31
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
|
|
32
|
+
createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
|
|
33
|
+
}
|
|
34
|
+
declare const aimyapi: AIMyAPIModuleExports;
|
|
35
|
+
|
|
36
|
+
export { type AIMyAPIInstance, type AIMyAPIModuleExports, type AIMyAPIOptions, type GenerateCodeResult, aimyapi, createBasePrompt, generateCode };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
|
|
2
|
+
import { QuickJSWASMModule } from 'quickjs-emscripten';
|
|
3
|
+
|
|
4
|
+
declare function createBasePrompt(apiFilePath: string, documentationPath: string): string;
|
|
5
|
+
interface GenerateCodeResult {
|
|
6
|
+
code: string;
|
|
7
|
+
loggableCode: string;
|
|
8
|
+
rawResponse?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
|
|
11
|
+
interface AIMyAPIOptions {
|
|
12
|
+
apiObject: object;
|
|
13
|
+
apiExports: object;
|
|
14
|
+
apiWhitelist?: string[];
|
|
15
|
+
apiGlobals?: object;
|
|
16
|
+
apiDefFilePath: string;
|
|
17
|
+
apiGlobalName?: string;
|
|
18
|
+
apiDocsPath?: string;
|
|
19
|
+
debug?: boolean;
|
|
20
|
+
model?: string;
|
|
21
|
+
}
|
|
22
|
+
interface AIMyAPIInstance {
|
|
23
|
+
options: AIMyAPIOptions;
|
|
24
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[]) => Promise<GenerateCodeResult>;
|
|
25
|
+
runCode: (task: string) => Promise<void>;
|
|
26
|
+
processRequest: (userQuery: string, context?: object) => Promise<GenerateCodeResult>;
|
|
27
|
+
}
|
|
28
|
+
interface AIMyAPIModuleExports {
|
|
29
|
+
createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
|
|
30
|
+
createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
|
|
31
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
|
|
32
|
+
createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
|
|
33
|
+
}
|
|
34
|
+
declare const aimyapi: AIMyAPIModuleExports;
|
|
35
|
+
|
|
36
|
+
export { type AIMyAPIInstance, type AIMyAPIModuleExports, type AIMyAPIOptions, type GenerateCodeResult, aimyapi, createBasePrompt, generateCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { QuickJSWASMModule } from
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
|
|
2
|
+
import { QuickJSWASMModule } from 'quickjs-emscripten';
|
|
3
|
+
|
|
4
|
+
declare function createBasePrompt(apiFilePath: string, documentationPath: string): string;
|
|
5
|
+
interface GenerateCodeResult {
|
|
5
6
|
code: string;
|
|
6
7
|
loggableCode: string;
|
|
7
8
|
rawResponse?: string;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
|
|
11
|
+
interface AIMyAPIOptions {
|
|
11
12
|
apiObject: object;
|
|
12
13
|
apiExports: object;
|
|
13
14
|
apiWhitelist?: string[];
|
|
@@ -16,18 +17,20 @@ export interface AIMyAPIOptions {
|
|
|
16
17
|
apiGlobalName?: string;
|
|
17
18
|
apiDocsPath?: string;
|
|
18
19
|
debug?: boolean;
|
|
20
|
+
model?: string;
|
|
19
21
|
}
|
|
20
|
-
|
|
22
|
+
interface AIMyAPIInstance {
|
|
21
23
|
options: AIMyAPIOptions;
|
|
22
|
-
generateCode: (queryText: string, userChatHistory:
|
|
24
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[]) => Promise<GenerateCodeResult>;
|
|
23
25
|
runCode: (task: string) => Promise<void>;
|
|
24
26
|
processRequest: (userQuery: string, context?: object) => Promise<GenerateCodeResult>;
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
interface AIMyAPIModuleExports {
|
|
27
29
|
createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
|
|
28
30
|
createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
|
|
29
|
-
generateCode: (queryText: string, userChatHistory:
|
|
31
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
|
|
30
32
|
createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
|
|
31
33
|
}
|
|
32
34
|
declare const aimyapi: AIMyAPIModuleExports;
|
|
33
|
-
|
|
35
|
+
|
|
36
|
+
export { type AIMyAPIInstance, type AIMyAPIModuleExports, type AIMyAPIOptions, type GenerateCodeResult, aimyapi, createBasePrompt, generateCode };
|