aimyapi 0.1.8 → 0.1.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 +9 -13
- package/dist/index.d.ts +13 -8
- package/dist/index.js +15 -20
- package/example/example1.ts +7 -7
- package/example/example2.ts +6 -6
- package/example/ordering_api.md +47 -73
- package/example/ordering_api_impl.ts +8 -5
- package/example/sales_api.md +1 -8
- package/lib/index.ts +33 -33
- package/package.json +2 -2
- package/prompts/create-task-prompt.md +3 -1
package/README.md
CHANGED
|
@@ -264,7 +264,7 @@ import path from "path";
|
|
|
264
264
|
console.log(`Query: ${query}`)
|
|
265
265
|
|
|
266
266
|
// generate the code for this query
|
|
267
|
-
const
|
|
267
|
+
const codeResult = await aimyapi.generateCode(query, api._getHistory());
|
|
268
268
|
|
|
269
269
|
api._addMessageToHistory({
|
|
270
270
|
content: query,
|
|
@@ -273,13 +273,13 @@ import path from "path";
|
|
|
273
273
|
});
|
|
274
274
|
|
|
275
275
|
api._addMessageToHistory({
|
|
276
|
-
content: '```\n' +
|
|
276
|
+
content: '```\n' + codeResult.loggableCode + '\n```',
|
|
277
277
|
role: "assistant",
|
|
278
278
|
name: "assistant",
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
// run the code in the sandbox
|
|
282
|
-
await aimyapi.runCode(code);
|
|
282
|
+
await aimyapi.runCode(codeResult.code);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
await runQuery("How's the burger here?");
|
|
@@ -389,24 +389,20 @@ user: How are you today?
|
|
|
389
389
|
|
|
390
390
|
assistant:
|
|
391
391
|
\`\`\`
|
|
392
|
-
|
|
393
|
-
(async() {
|
|
394
|
-
try {
|
|
395
|
-
api.print("I'm great, thanks for asking!");
|
|
396
|
-
} catch(e) {
|
|
397
|
-
console.error(e);
|
|
398
|
-
}
|
|
399
|
-
})();
|
|
392
|
+
api.print("I'm great, thanks for asking!");
|
|
400
393
|
\`\`\`
|
|
394
|
+
|
|
401
395
|
```
|
|
402
396
|
|
|
403
397
|
Aside from the code generation piece, documenting your API with clearly named functions and comments is important so that the LLM understands how it can be used. A big part of using AIMyAPI is testing out usecases and looking at the code that is generated. Problems can be solved by how you name your api, comments in the api, and examples.
|
|
404
398
|
|
|
405
399
|
## A note about history
|
|
406
400
|
|
|
407
|
-
If you plan to use history, it is vital that you include the generated code in the history. Otherwise, the LLM will start to think that it doesn't need to generate code.
|
|
401
|
+
If you plan to use history, it is vital that you include the generated code in the history. Otherwise, the LLM will start to think that it doesn't need to generate code. Logging is also necessary for keeping track of Id's from past requests so that future requests can leverage that information.
|
|
402
|
+
|
|
403
|
+
See example2 for more an example on how to do this.
|
|
408
404
|
|
|
409
|
-
|
|
405
|
+
TODO: Add more details explaining how this is done.
|
|
410
406
|
|
|
411
407
|
## Safety notes:
|
|
412
408
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ChatCompletionRequestMessage } from "openai";
|
|
2
2
|
import { QuickJSWASMModule } from "quickjs-emscripten";
|
|
3
3
|
export declare function createBasePrompt(apiFilePath: string, documentationPath: string): string;
|
|
4
|
-
export
|
|
4
|
+
export interface GenerateCodeResult {
|
|
5
|
+
code: string;
|
|
6
|
+
loggableCode: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[], createTaskPrompt: string, apiPath: string, debug?: boolean) => Promise<GenerateCodeResult>;
|
|
5
9
|
export interface AIMyAPIOptions {
|
|
6
10
|
apiObject: object;
|
|
7
11
|
apiExports: object;
|
|
@@ -12,16 +16,17 @@ export interface AIMyAPIOptions {
|
|
|
12
16
|
apiDocsPath?: string;
|
|
13
17
|
debug?: boolean;
|
|
14
18
|
}
|
|
15
|
-
export interface
|
|
16
|
-
|
|
19
|
+
export interface AIMyAPIInstance {
|
|
20
|
+
options: AIMyAPIOptions;
|
|
21
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[]) => Promise<GenerateCodeResult>;
|
|
17
22
|
runCode: (task: string) => Promise<void>;
|
|
18
|
-
processRequest: (userQuery: string, context?: object) => Promise<
|
|
23
|
+
processRequest: (userQuery: string, context?: object) => Promise<GenerateCodeResult>;
|
|
19
24
|
}
|
|
20
|
-
export interface
|
|
21
|
-
createWithAPI: (options: AIMyAPIOptions) => Promise<
|
|
25
|
+
export interface AIMyAPIModuleExports {
|
|
26
|
+
createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
|
|
22
27
|
createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
|
|
23
|
-
generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<
|
|
28
|
+
generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
|
|
24
29
|
createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
|
|
25
30
|
}
|
|
26
|
-
declare const aimyapi:
|
|
31
|
+
declare const aimyapi: AIMyAPIModuleExports;
|
|
27
32
|
export default aimyapi;
|
package/dist/index.js
CHANGED
|
@@ -47,16 +47,7 @@ const generateCode = async function (queryText, userChatHistory, createTaskPromp
|
|
|
47
47
|
name: "user"
|
|
48
48
|
}
|
|
49
49
|
];
|
|
50
|
-
// TODO: I should switch this back to gpt3.5 turbo since it's cheaper
|
|
51
50
|
try {
|
|
52
|
-
// const task = await openai.createCompletion(
|
|
53
|
-
// {
|
|
54
|
-
// model: "text-davinci-003",
|
|
55
|
-
// prompt,
|
|
56
|
-
// temperature: 0.1,
|
|
57
|
-
// max_tokens: 1100,
|
|
58
|
-
// }
|
|
59
|
-
// );
|
|
60
51
|
const results = await openai.createChatCompletion({
|
|
61
52
|
model: "gpt-3.5-turbo",
|
|
62
53
|
messages: messages,
|
|
@@ -71,16 +62,19 @@ const generateCode = async function (queryText, userChatHistory, createTaskPromp
|
|
|
71
62
|
// Return only the code between ``` and ``` (usually at the end of the completion)
|
|
72
63
|
const codeStart = response.indexOf('```');
|
|
73
64
|
const codeEnd = response.lastIndexOf('```');
|
|
74
|
-
|
|
75
|
-
|
|
65
|
+
// error, no code detected inside the response
|
|
66
|
+
if (codeStart === -1 || codeEnd === -1 || codeStart === codeEnd) {
|
|
67
|
+
return { code: '', loggableCode: '' };
|
|
68
|
+
}
|
|
76
69
|
generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
const codeHeader = `// Query: ${queryText}\nimport * as ApiDefs from '${apiPath}'\n(async() {\n\ttry {`;
|
|
71
|
+
const codeFooter = `\n\t} catch(err) {\n\t\tconsole.error(err);\n\t}\n})();`;
|
|
72
|
+
return { code: codeHeader + generatedCode + codeFooter, loggableCode: generatedCode };
|
|
79
73
|
}
|
|
80
74
|
catch (err) {
|
|
81
75
|
console.error(err);
|
|
82
76
|
console.log("Prompt", messages);
|
|
83
|
-
return '';
|
|
77
|
+
return { code: '', loggableCode: '' };
|
|
84
78
|
}
|
|
85
79
|
};
|
|
86
80
|
exports.generateCode = generateCode;
|
|
@@ -101,9 +95,10 @@ async function createWithAPI(options) {
|
|
|
101
95
|
const { apiObject, apiWhitelist, apiGlobalName, apiExports, apiDefFilePath, apiDocsPath, debug } = options;
|
|
102
96
|
const createTaskPrompt = createBasePrompt(apiDefFilePath, apiDocsPath);
|
|
103
97
|
return {
|
|
98
|
+
options,
|
|
104
99
|
generateCode: async function (queryText, userChatHistory, currentContext = undefined) {
|
|
105
100
|
if (!queryText)
|
|
106
|
-
return '';
|
|
101
|
+
return { code: '', loggableCode: '' };
|
|
107
102
|
return await (0, exports.generateCode)(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug);
|
|
108
103
|
},
|
|
109
104
|
runCode: async function (generatedCode) {
|
|
@@ -127,10 +122,13 @@ async function createWithAPI(options) {
|
|
|
127
122
|
...apiGlobals,
|
|
128
123
|
[apiGlobalName]: {
|
|
129
124
|
value: apiObject,
|
|
130
|
-
apiWhitelist
|
|
125
|
+
whitelist: apiWhitelist
|
|
131
126
|
}
|
|
132
127
|
}, options.debug);
|
|
133
128
|
try {
|
|
129
|
+
if (debug) {
|
|
130
|
+
console.log("Running Code:\n", generatedCode);
|
|
131
|
+
}
|
|
134
132
|
const res = await runTask(generatedCode);
|
|
135
133
|
if (!res) {
|
|
136
134
|
console.error("Task unsuccessful");
|
|
@@ -160,11 +158,8 @@ async function createWithAPI(options) {
|
|
|
160
158
|
console.time("Generate Task");
|
|
161
159
|
const generatedCode = await (0, exports.generateCode)(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
|
|
162
160
|
console.timeEnd("Generate Task");
|
|
163
|
-
if (debug) {
|
|
164
|
-
console.log("Generated Code:", generatedCode);
|
|
165
|
-
}
|
|
166
161
|
console.time("Run Code");
|
|
167
|
-
await this.runCode(generatedCode);
|
|
162
|
+
await this.runCode(generatedCode.code);
|
|
168
163
|
console.timeEnd("Run Code");
|
|
169
164
|
return generatedCode;
|
|
170
165
|
}
|
package/example/example1.ts
CHANGED
|
@@ -14,17 +14,17 @@ import { API } from "./sales_api_impl";
|
|
|
14
14
|
apiExports: APIExports,
|
|
15
15
|
apiDefFilePath: path.join(__dirname, "./sales_api.ts"),
|
|
16
16
|
apiDocsPath: path.join(__dirname, "./sales_api.md"),
|
|
17
|
-
debug:
|
|
17
|
+
debug: true,
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
console.log("Print 'hello' three times.")
|
|
21
|
-
await aimyapi.processRequest("Print 'hello' three times.");
|
|
20
|
+
// console.log("Print 'hello' three times.")
|
|
21
|
+
// await aimyapi.processRequest("Print 'hello' three times.");
|
|
22
22
|
|
|
23
|
-
console.log("What month had the highest sales in 2020 for any business unit?")
|
|
24
|
-
await aimyapi.processRequest("What was our best month in 2020");
|
|
23
|
+
// console.log("What month had the highest sales in 2020 for any business unit?")
|
|
24
|
+
// await aimyapi.processRequest("What was our best month in 2020");
|
|
25
25
|
|
|
26
|
-
console.log("Which business unit had the highest sales in 2020?")
|
|
27
|
-
await aimyapi.processRequest("Which business unit had the highest sales in 2020?");
|
|
26
|
+
// console.log("Which business unit had the highest sales in 2020?")
|
|
27
|
+
// await aimyapi.processRequest("Which business unit had the highest sales in 2020?");
|
|
28
28
|
|
|
29
29
|
console.log("Compute the total sales for each month in 2020 then email the top 3 to test@email.com")
|
|
30
30
|
await aimyapi.processRequest("Compute the total sales for each month in 2020 then email the top 3 to test@email.com");
|
package/example/example2.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import AIMyAPI from "../lib";
|
|
2
|
-
import { OrderingAPI } from "./ordering_api_impl";
|
|
3
|
-
import * as APIExports from "./ordering_api";
|
|
4
1
|
import path from "path";
|
|
2
|
+
import AIMyAPI, { GenerateCodeResult } from "../lib";
|
|
3
|
+
import * as APIExports from "./ordering_api";
|
|
4
|
+
import { OrderingAPI } from "./ordering_api_impl";
|
|
5
5
|
|
|
6
6
|
// More complex fast food ordering example that uses chat history.
|
|
7
7
|
// Fast food ordering example.
|
|
@@ -24,7 +24,7 @@ import path from "path";
|
|
|
24
24
|
console.log(`Query: ${query}`)
|
|
25
25
|
|
|
26
26
|
// generate the code for this query
|
|
27
|
-
const
|
|
27
|
+
const codeResult:GenerateCodeResult = await aimyapi.generateCode(query, api._getHistory());
|
|
28
28
|
|
|
29
29
|
api._addMessageToHistory({
|
|
30
30
|
content: query,
|
|
@@ -33,13 +33,13 @@ import path from "path";
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
api._addMessageToHistory({
|
|
36
|
-
content: '```\n' +
|
|
36
|
+
content: '```\n' + codeResult.loggableCode + '\n```',
|
|
37
37
|
role: "assistant",
|
|
38
38
|
name: "assistant",
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
// run the code in the sandbox
|
|
42
|
-
await aimyapi.runCode(code);
|
|
42
|
+
await aimyapi.runCode(codeResult.code);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
await runQuery("How's the burger here?");
|
package/example/ordering_api.md
CHANGED
|
@@ -10,109 +10,83 @@ user: How are you today?
|
|
|
10
10
|
|
|
11
11
|
assistant:
|
|
12
12
|
```
|
|
13
|
-
|
|
14
|
-
(async() {
|
|
15
|
-
try {
|
|
16
|
-
orderingApi.respondToUser("I'm great, thanks for asking!");
|
|
17
|
-
} catch(e) {
|
|
18
|
-
console.error(e);
|
|
19
|
-
}
|
|
20
|
-
})();
|
|
13
|
+
orderingApi.respondToUser("I'm great, thanks for asking!");
|
|
21
14
|
```
|
|
22
15
|
|
|
23
16
|
user: Add a hamburger with no cheese to my order
|
|
24
17
|
|
|
25
18
|
assistant:
|
|
26
19
|
```
|
|
27
|
-
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
orderingApi.addItemToOrder(itemName, undefined, item.toppings.filter( topping => topping.name != "cheese") );
|
|
37
|
-
orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
|
|
38
|
-
} catch(e) {
|
|
39
|
-
console.error(e);
|
|
40
|
-
}
|
|
41
|
-
})();
|
|
20
|
+
const itemName = "Hamburger";
|
|
21
|
+
const item = ApiDefs.Menu.find((item) => item.name === itemName);
|
|
22
|
+
if (!item) {
|
|
23
|
+
throw new Error(`Item with name "${itemName}" not found`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
orderingApi.addItemToOrder(itemName, undefined, item.toppings.filter( topping => topping.name != "cheese") );
|
|
27
|
+
orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
|
|
42
28
|
```
|
|
43
29
|
|
|
44
|
-
|
|
30
|
+
log: Added Hamburger with id 1
|
|
45
31
|
|
|
46
32
|
user: I'd like a large pizza with mushrooms
|
|
47
33
|
|
|
48
34
|
assistant:
|
|
49
35
|
```
|
|
50
|
-
|
|
51
|
-
(
|
|
52
|
-
try {
|
|
53
|
-
orderingApi.addItemToOrder("Pizza", ["Large"], ["mushrooms"]);
|
|
54
|
-
orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
|
|
55
|
-
} catch(err) {
|
|
56
|
-
orderingApi.respondToUser("Apologies, something went wrong with that request.");
|
|
57
|
-
}
|
|
58
|
-
})();
|
|
36
|
+
orderingApi.addItemToOrder("Pizza", ["Large"], ["mushrooms"]);
|
|
37
|
+
orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
|
|
59
38
|
```
|
|
60
39
|
|
|
61
40
|
user: Add a hamburger with bacon
|
|
62
41
|
|
|
63
42
|
assistant:
|
|
64
43
|
```
|
|
65
|
-
|
|
66
|
-
(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
orderingApi.addItemToOrder(itemName, undefined, [...item.toppings, "bacon"]);
|
|
75
|
-
orderingApi.respondToUser("Ok, I added a Hamburger with no cheese or onions. What else would you like?");
|
|
76
|
-
} catch(e) {
|
|
77
|
-
console.error(e);
|
|
78
|
-
}
|
|
79
|
-
})();
|
|
44
|
+
const itemName = "Hamburger";
|
|
45
|
+
const item = ApiDefs.Menu.find((item) => item.name === itemName);
|
|
46
|
+
if (!item) {
|
|
47
|
+
throw new Error(`Item with name "${itemName}" not found`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
orderingApi.addItemToOrder(itemName, undefined, [...item.toppings, "bacon"]);
|
|
51
|
+
orderingApi.respondToUser("Ok, I added a Hamburger with no cheese or onions. What else would you like?");
|
|
80
52
|
```
|
|
81
53
|
|
|
82
|
-
|
|
54
|
+
log: Added Hamburger with id 2
|
|
83
55
|
|
|
84
56
|
user: Add jalapenos to that
|
|
85
57
|
|
|
86
58
|
assistant:
|
|
87
59
|
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
} else {
|
|
97
|
-
orderingApi.respondToUser("Hmm, I can't find that item.");
|
|
98
|
-
}
|
|
99
|
-
} catch(e) {
|
|
100
|
-
orderingApi.respondToUser("Apologies, something went wrong with that request.");
|
|
101
|
-
console.error(e);
|
|
102
|
-
}
|
|
103
|
-
})();
|
|
60
|
+
const existingItem = orderingApi.getItemInOrder("2");
|
|
61
|
+
|
|
62
|
+
if(existingItem) {
|
|
63
|
+
orderingApi.modifyItemInOrder("2", existingItem.customizations.map(item => item.name), [...existingItem.toppings, "jalapenos"]);
|
|
64
|
+
orderingApi.respondToUser("Ok, I added jalapenos to your Hamburger");
|
|
65
|
+
} else {
|
|
66
|
+
orderingApi.respondToUser("Hmm, I can't find that item.");
|
|
67
|
+
}
|
|
104
68
|
```
|
|
105
69
|
|
|
70
|
+
user: Add a hamburger with no lettuce
|
|
71
|
+
|
|
72
|
+
assistant:
|
|
73
|
+
```
|
|
74
|
+
const itemName = "Hamburger";
|
|
75
|
+
const item = ApiDefs.Menu.find((item) => item.name === itemName);
|
|
76
|
+
if (!item) {
|
|
77
|
+
throw new Error(`Item with name "${itemName}" not found`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
orderingApi.addItemToOrder(itemName, undefined, [...item.toppings.filter(topping => topping != "lettuce")]);
|
|
81
|
+
orderingApi.respondToUser("Ok, I added a Hamburger with no cheese or onions. What else would you like?");
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
log: Added Hamburger with id 2
|
|
85
|
+
|
|
86
|
+
|
|
106
87
|
user: I want an elephant.
|
|
107
88
|
|
|
108
89
|
assistant:
|
|
109
90
|
```
|
|
110
|
-
|
|
111
|
-
(async() {
|
|
112
|
-
try {
|
|
113
|
-
orderingApi.respondToUser("I'm sorry, but that isn't on our menu.");
|
|
114
|
-
} catch(e) {
|
|
115
|
-
console.error(e);
|
|
116
|
-
}
|
|
117
|
-
})();
|
|
91
|
+
orderingApi.respondToUser("I'm sorry, but that isn't on our menu.");
|
|
118
92
|
```
|
|
@@ -87,12 +87,13 @@ export class OrderingAPI implements OrderingAPIInterface {
|
|
|
87
87
|
|
|
88
88
|
this._history.push({
|
|
89
89
|
role: "user",
|
|
90
|
-
|
|
90
|
+
name: "log",
|
|
91
|
+
content: `added added ${itemName} with id ${newItem.orderId}`,
|
|
91
92
|
});
|
|
92
93
|
this.displayItem(newItem, true);
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
getItemInOrder(itemOrderId: string): MenuItemBase {
|
|
96
|
+
getItemInOrder(itemOrderId: string): MenuItemBase | undefined {
|
|
96
97
|
const item = this._order.find((item) => item.orderId === itemOrderId);
|
|
97
98
|
if (!item) {
|
|
98
99
|
return undefined;
|
|
@@ -106,7 +107,8 @@ export class OrderingAPI implements OrderingAPIInterface {
|
|
|
106
107
|
|
|
107
108
|
this._history.push({
|
|
108
109
|
role: "user",
|
|
109
|
-
|
|
110
|
+
name: "log",
|
|
111
|
+
content: `removed item ${itemOrderId}`,
|
|
110
112
|
});
|
|
111
113
|
this.respondToUser(`Removed item ${itemOrderId}`);
|
|
112
114
|
}
|
|
@@ -140,7 +142,8 @@ export class OrderingAPI implements OrderingAPIInterface {
|
|
|
140
142
|
|
|
141
143
|
this._history.push({
|
|
142
144
|
role: "user",
|
|
143
|
-
|
|
145
|
+
name: "log",
|
|
146
|
+
content: `modified item ${itemOrderId}`,
|
|
144
147
|
});
|
|
145
148
|
this.respondToUser(`Modified item ${itemOrderId}`);
|
|
146
149
|
}
|
|
@@ -188,7 +191,7 @@ export class OrderingAPI implements OrderingAPIInterface {
|
|
|
188
191
|
displayOrder() {
|
|
189
192
|
this.respondToUser("----\n\nDisplaying order:\n\n");
|
|
190
193
|
this._order.forEach((item) => this.displayItem(item));
|
|
191
|
-
this.respondToUser(`--\tTotal:\t\t$${this.getOrderTotal()}`);
|
|
194
|
+
this.respondToUser(`--\tTotal:\t\t$${this.getOrderTotal().toFixed(2)}`);
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
_addMessageToHistory(message: ChatCompletionRequestMessage) {
|
package/example/sales_api.md
CHANGED
package/lib/index.ts
CHANGED
|
@@ -31,8 +31,13 @@ export function createBasePrompt(apiFilePath:string, documentationPath: string):
|
|
|
31
31
|
return createTaskPrompt;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
export interface GenerateCodeResult {
|
|
35
|
+
code: string;
|
|
36
|
+
loggableCode: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
// FIXME: add an options parameter and allow specifying the token limit
|
|
35
|
-
export const generateCode = async function(queryText:string, userChatHistory:ChatCompletionRequestMessage[], createTaskPrompt:string, apiPath:string, debug:boolean = false): Promise<
|
|
40
|
+
export const generateCode = async function(queryText:string, userChatHistory:ChatCompletionRequestMessage[], createTaskPrompt:string, apiPath:string, debug:boolean = false): Promise<GenerateCodeResult> {
|
|
36
41
|
if(!queryText)
|
|
37
42
|
return;
|
|
38
43
|
|
|
@@ -50,17 +55,7 @@ export const generateCode = async function(queryText:string, userChatHistory:Cha
|
|
|
50
55
|
name: "user"
|
|
51
56
|
}
|
|
52
57
|
];
|
|
53
|
-
// TODO: I should switch this back to gpt3.5 turbo since it's cheaper
|
|
54
58
|
try {
|
|
55
|
-
// const task = await openai.createCompletion(
|
|
56
|
-
// {
|
|
57
|
-
// model: "text-davinci-003",
|
|
58
|
-
// prompt,
|
|
59
|
-
// temperature: 0.1,
|
|
60
|
-
// max_tokens: 1100,
|
|
61
|
-
// }
|
|
62
|
-
// );
|
|
63
|
-
|
|
64
59
|
const results = await openai.createChatCompletion({
|
|
65
60
|
model: "gpt-3.5-turbo",
|
|
66
61
|
messages: messages,
|
|
@@ -81,17 +76,20 @@ export const generateCode = async function(queryText:string, userChatHistory:Cha
|
|
|
81
76
|
const codeStart = response.indexOf('```');
|
|
82
77
|
const codeEnd = response.lastIndexOf('```');
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
// error, no code detected inside the response
|
|
80
|
+
if(codeStart === -1 || codeEnd === -1 || codeStart === codeEnd) {
|
|
81
|
+
return { code: '', loggableCode: '' };
|
|
82
|
+
}
|
|
86
83
|
|
|
87
84
|
generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
const codeHeader = `// Query: ${queryText}\nimport * as ApiDefs from '${apiPath}'\n(async() {\n\ttry {`;
|
|
87
|
+
const codeFooter = `\n\t} catch(err) {\n\t\tconsole.error(err);\n\t}\n})();`;
|
|
88
|
+
return { code: codeHeader + generatedCode + codeFooter, loggableCode: generatedCode };
|
|
91
89
|
} catch(err) {
|
|
92
90
|
console.error(err);
|
|
93
91
|
console.log("Prompt", messages);
|
|
94
|
-
return '';
|
|
92
|
+
return { code: '', loggableCode: '' };
|
|
95
93
|
}
|
|
96
94
|
};
|
|
97
95
|
|
|
@@ -108,16 +106,17 @@ export interface AIMyAPIOptions {
|
|
|
108
106
|
debug?: boolean;
|
|
109
107
|
};
|
|
110
108
|
|
|
111
|
-
export interface
|
|
109
|
+
export interface AIMyAPIInstance {
|
|
112
110
|
// see xample 2
|
|
113
|
-
|
|
111
|
+
options:AIMyAPIOptions;
|
|
112
|
+
generateCode: (queryText:string, userChatHistory:ChatCompletionRequestMessage[]) => Promise<GenerateCodeResult>;
|
|
114
113
|
runCode: (task:string) => Promise<void>;
|
|
115
114
|
// run a single request with no history
|
|
116
|
-
processRequest: (userQuery:string, context?: object) => Promise<
|
|
115
|
+
processRequest: (userQuery:string, context?: object) => Promise<GenerateCodeResult>;
|
|
117
116
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
async function createWithAPI(options:AIMyAPIOptions): Promise<
|
|
119
|
+
async function createWithAPI(options:AIMyAPIOptions): Promise<AIMyAPIInstance> {
|
|
121
120
|
// extend options with defaults
|
|
122
121
|
options = {
|
|
123
122
|
apiGlobalName: "api",
|
|
@@ -136,9 +135,10 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExpor
|
|
|
136
135
|
const createTaskPrompt = createBasePrompt( apiDefFilePath, apiDocsPath);
|
|
137
136
|
|
|
138
137
|
return {
|
|
138
|
+
options,
|
|
139
139
|
generateCode: async function(queryText:string, userChatHistory:ChatCompletionRequestMessage[], currentContext:any = undefined) {
|
|
140
140
|
if(!queryText)
|
|
141
|
-
return '';
|
|
141
|
+
return { code: '', loggableCode: '' };
|
|
142
142
|
|
|
143
143
|
return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug);
|
|
144
144
|
},
|
|
@@ -166,11 +166,15 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExpor
|
|
|
166
166
|
...apiGlobals,
|
|
167
167
|
[apiGlobalName]: {
|
|
168
168
|
value: apiObject,
|
|
169
|
-
apiWhitelist
|
|
169
|
+
whitelist: apiWhitelist
|
|
170
170
|
}
|
|
171
171
|
}, options.debug);
|
|
172
172
|
|
|
173
173
|
try {
|
|
174
|
+
if(debug) {
|
|
175
|
+
console.log("Running Code:\n", generatedCode);
|
|
176
|
+
}
|
|
177
|
+
|
|
174
178
|
const res = await runTask(generatedCode);
|
|
175
179
|
|
|
176
180
|
if(!res) {
|
|
@@ -196,7 +200,7 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExpor
|
|
|
196
200
|
vm.dispose()
|
|
197
201
|
|
|
198
202
|
},
|
|
199
|
-
processRequest: async function (userQuery, currentContext:any = undefined):Promise<
|
|
203
|
+
processRequest: async function (userQuery, currentContext:any = undefined):Promise<GenerateCodeResult> {
|
|
200
204
|
// Create prompt
|
|
201
205
|
|
|
202
206
|
if(debug) {
|
|
@@ -205,15 +209,11 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExpor
|
|
|
205
209
|
|
|
206
210
|
// Generate Code
|
|
207
211
|
console.time("Generate Task")
|
|
208
|
-
const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : "" ), apiDefFilePath);
|
|
212
|
+
const generatedCode:GenerateCodeResult = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : "" ), apiDefFilePath);
|
|
209
213
|
console.timeEnd("Generate Task")
|
|
210
214
|
|
|
211
|
-
if(debug) {
|
|
212
|
-
console.log("Generated Code:", generatedCode);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
215
|
console.time("Run Code")
|
|
216
|
-
await this.runCode(generatedCode);
|
|
216
|
+
await this.runCode(generatedCode.code);
|
|
217
217
|
console.timeEnd("Run Code")
|
|
218
218
|
|
|
219
219
|
return generatedCode;
|
|
@@ -222,15 +222,15 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExpor
|
|
|
222
222
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
export interface
|
|
226
|
-
createWithAPI: (options:AIMyAPIOptions) => Promise<
|
|
225
|
+
export interface AIMyAPIModuleExports {
|
|
226
|
+
createWithAPI: (options:AIMyAPIOptions) => Promise<AIMyAPIInstance>;
|
|
227
227
|
|
|
228
228
|
createBasePrompt: (apiFilePath:string, documentationPath: string) => string;
|
|
229
|
-
generateCode: (queryText:string, userChatHistory:ChatCompletionRequestMessage[], createTaskPrompt:string, apiPath:string, debug:boolean) => Promise<
|
|
229
|
+
generateCode: (queryText:string, userChatHistory:ChatCompletionRequestMessage[], createTaskPrompt:string, apiPath:string, debug:boolean) => Promise<GenerateCodeResult>;
|
|
230
230
|
createSandbox: (QuickJS:QuickJSWASMModule, globals: any) => Promise<any>;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
const aimyapi:
|
|
233
|
+
const aimyapi:AIMyAPIModuleExports = {
|
|
234
234
|
// Standard way of using the library
|
|
235
235
|
createWithAPI,
|
|
236
236
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aimyapi",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "AI My API! Use LLMs to create small programs that safely* run and make calls against your API.",
|
|
3
|
+
"version": "0.1.10",
|
|
4
|
+
"description": "AI My API! Use LLMs to create small programs that safely* run and make calls against your API. Similar to ChatGPT's Code Interpreter.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"directories": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
You are a helpful assistant who speaks only in Typescript.
|
|
2
|
-
You fulfill user requests by writing code.
|
|
2
|
+
You work just like a regular assistant, but you fulfill user requests by writing code.
|
|
3
3
|
You comment your code and are sure to properly escape your strings and follow good programming practices.
|
|
4
4
|
|
|
5
5
|
Here is the API that you will use:
|
|
@@ -11,6 +11,8 @@ Here is the API that you will use:
|
|
|
11
11
|
|
|
12
12
|
Documentation:
|
|
13
13
|
|
|
14
|
+
Note: the api definitions are available as `ApiDefs`;
|
|
15
|
+
|
|
14
16
|
{{DOCUMENTATION}}
|
|
15
17
|
|
|
16
18
|
Current Context:
|