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,14 @@
|
|
|
1
|
+
import "quickjs-emscripten";
|
|
2
|
+
export interface GlobalOption {
|
|
3
|
+
value: any;
|
|
4
|
+
whitelist?: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface Globals {
|
|
7
|
+
[key: string]: GlobalOption;
|
|
8
|
+
}
|
|
9
|
+
export default function createSandbox(QuickJS: any, requireLookup?: any, globals?: Globals, debug?: boolean): Promise<{
|
|
10
|
+
vm: any;
|
|
11
|
+
getLastError: () => string;
|
|
12
|
+
isAsyncProcessRunning: () => boolean;
|
|
13
|
+
runTask: (task: string) => boolean;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
require("quickjs-emscripten");
|
|
27
|
+
const ts = __importStar(require("typescript"));
|
|
28
|
+
const sandbox_wrappers_1 = require("./sandbox-wrappers");
|
|
29
|
+
// Should we use "noEmitOnError": true ?
|
|
30
|
+
function tsCompile(source, options = null) {
|
|
31
|
+
// Default options -- you could also perform a merge, or use the project tsconfig.json
|
|
32
|
+
if (null === options) {
|
|
33
|
+
options = {
|
|
34
|
+
compilerOptions: {
|
|
35
|
+
target: ts.ScriptTarget.ES2020,
|
|
36
|
+
module: ts.ModuleKind.None,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return ts.transpileModule(source, options).outputText;
|
|
41
|
+
}
|
|
42
|
+
// function whitelist can be produced using something like:
|
|
43
|
+
// const assistantFunctions = Object.getOwnPropertyNames(Object.getPrototypeOf(apiObject))
|
|
44
|
+
// .filter((f) => f !== "constructor" && !f.startsWith("_"));
|
|
45
|
+
// Is there some way we can treat the API and globals the same?
|
|
46
|
+
// We could just provide an object for all globals (including the API) and also have the whitelist as a parameter..
|
|
47
|
+
async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug = false) {
|
|
48
|
+
const vm = QuickJS.newContext();
|
|
49
|
+
let errorState = false;
|
|
50
|
+
let lastError = "";
|
|
51
|
+
let asyncProcessesRunning = 0;
|
|
52
|
+
let beginAsyncProcess = () => {
|
|
53
|
+
asyncProcessesRunning++;
|
|
54
|
+
};
|
|
55
|
+
let endAsyncProcess = () => {
|
|
56
|
+
if (asyncProcessesRunning > 0) {
|
|
57
|
+
asyncProcessesRunning--;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
let isAsyncProcessRunning = () => {
|
|
61
|
+
//console.log("asyncProcessesRunning:", asyncProcessesRunning);
|
|
62
|
+
return asyncProcessesRunning > 0;
|
|
63
|
+
};
|
|
64
|
+
// const assistantHandle = wrapObjectWhitelist(vm, apiObject, functionWhitelist, beginAsyncProcess, endAsyncProcess);
|
|
65
|
+
// vm.setProp(vm.global, apiGlobalName, assistantHandle)
|
|
66
|
+
// assistantHandle.dispose();
|
|
67
|
+
const logHandle = vm.newFunction("log", (...args) => {
|
|
68
|
+
const nativeArgs = args.map(vm.dump);
|
|
69
|
+
console.log("QuickJS Log:", ...nativeArgs);
|
|
70
|
+
});
|
|
71
|
+
const consoleHandle = vm.newObject();
|
|
72
|
+
const exportsHandle = vm.newObject();
|
|
73
|
+
const errorHandle = vm.newFunction("error", (...args) => {
|
|
74
|
+
try {
|
|
75
|
+
const nativeArgs = args.map(vm.dump);
|
|
76
|
+
console.log("QuickJS console.error:", ...nativeArgs);
|
|
77
|
+
lastError = JSON.stringify(nativeArgs);
|
|
78
|
+
errorState = true;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.log("Error in error:", e);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
const globalNames = Object.getOwnPropertyNames(globals);
|
|
85
|
+
for (let i = 0; i < globalNames.length; i++) {
|
|
86
|
+
const globalOption = globals[globalNames[i]];
|
|
87
|
+
const globalObj = globalOption.whitelist
|
|
88
|
+
? (0, sandbox_wrappers_1.wrapObjectWhitelist)(vm, globalOption.value, globalOption.whitelist, beginAsyncProcess, endAsyncProcess)
|
|
89
|
+
: (0, sandbox_wrappers_1.wrap)(vm, globalOption.value, globalOption, beginAsyncProcess, endAsyncProcess);
|
|
90
|
+
vm.setProp(vm.global, globalNames[i], globalObj);
|
|
91
|
+
globalObj.dispose();
|
|
92
|
+
}
|
|
93
|
+
(0, sandbox_wrappers_1.injectTimingFunctions)(vm, beginAsyncProcess, endAsyncProcess);
|
|
94
|
+
const requireHandle = vm.newFunction("require", (...args) => {
|
|
95
|
+
const nativeArgs = args.map(vm.dump);
|
|
96
|
+
if (requireLookup[nativeArgs[0]]) {
|
|
97
|
+
const returnObj = (0, sandbox_wrappers_1.wrapObject)(vm, requireLookup[nativeArgs[0]], beginAsyncProcess, endAsyncProcess);
|
|
98
|
+
return returnObj;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return vm.undefined;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
vm.setProp(consoleHandle, "log", logHandle);
|
|
105
|
+
vm.setProp(consoleHandle, "error", errorHandle);
|
|
106
|
+
vm.setProp(vm.global, "require", requireHandle);
|
|
107
|
+
vm.setProp(vm.global, "console", consoleHandle);
|
|
108
|
+
vm.setProp(vm.global, "exports", exportsHandle);
|
|
109
|
+
consoleHandle.dispose();
|
|
110
|
+
logHandle.dispose();
|
|
111
|
+
exportsHandle.dispose();
|
|
112
|
+
errorHandle.dispose();
|
|
113
|
+
requireHandle.dispose();
|
|
114
|
+
return {
|
|
115
|
+
vm,
|
|
116
|
+
getLastError: () => {
|
|
117
|
+
return lastError;
|
|
118
|
+
},
|
|
119
|
+
isAsyncProcessRunning,
|
|
120
|
+
runTask: (task) => {
|
|
121
|
+
try {
|
|
122
|
+
const compiled = tsCompile(task);
|
|
123
|
+
if (!compiled || compiled.length === 0) {
|
|
124
|
+
console.log("Could not compile");
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
// View compiled typescript code for debugging
|
|
128
|
+
// if(debug)
|
|
129
|
+
// console.log(compiled);
|
|
130
|
+
errorState = false;
|
|
131
|
+
const result = vm.evalCode(compiled);
|
|
132
|
+
if (result.error) {
|
|
133
|
+
// log out the compiled program with line numbers
|
|
134
|
+
const lines = compiled.split("\n");
|
|
135
|
+
for (let i = 0; i < lines.length; i++) {
|
|
136
|
+
console.log(`${i + 1}: ${lines[i]}`);
|
|
137
|
+
}
|
|
138
|
+
console.log("Execution failed:", vm.dump(result.error));
|
|
139
|
+
result.error.dispose();
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
//console.log("Task Result:", vm.dump(result.value));
|
|
144
|
+
result.value.dispose();
|
|
145
|
+
if (errorState) {
|
|
146
|
+
const lines = compiled.split("\n");
|
|
147
|
+
for (let i = 0; i < lines.length; i++) {
|
|
148
|
+
console.log(`${i + 1}: ${lines[i]}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return !errorState;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
console.log(e);
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
exports.default = createSandbox;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function delay(time: any): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
import AIMyAPI from "../lib";
|
|
3
|
+
import { API } from "./sales_api_impl";
|
|
4
|
+
import * as APIExports from "./sales_api";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// Simpler example using no support for chat history;
|
|
9
|
+
|
|
10
|
+
(async () => {
|
|
11
|
+
const api = new API();
|
|
12
|
+
|
|
13
|
+
const aimyapi = await AIMyAPI.createWithAPI({
|
|
14
|
+
apiObject: api,
|
|
15
|
+
apiGlobalName: "api", // Should match whatever you declared as your global in your api.
|
|
16
|
+
apiExports: APIExports,
|
|
17
|
+
apiDefFilePath: path.join(__dirname, "./sales_api.ts"),
|
|
18
|
+
apiDocsPath: path.join(__dirname, "./sales_api.md"),
|
|
19
|
+
debug: false,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
console.log("Print 'hello' three times.")
|
|
23
|
+
await aimyapi.processRequest("Print 'hello' three times.");
|
|
24
|
+
|
|
25
|
+
console.log("What was our best month in 2020")
|
|
26
|
+
await aimyapi.processRequest("What was our best month in 2020");
|
|
27
|
+
|
|
28
|
+
console.log("Which business unit had the highest sales in 2020?")
|
|
29
|
+
await aimyapi.processRequest("Which business unit had the highest sales in 2020?");
|
|
30
|
+
|
|
31
|
+
console.log("Compute the total sales for each month in 2020 then email the top 3 to test@email.com")
|
|
32
|
+
await aimyapi.processRequest("Compute the total sales for each month in 2020 then email the top 3 to test@email.com");
|
|
33
|
+
})();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
import AIMyAPI from "../lib";
|
|
3
|
+
import { OrderingAPI } from "./ordering_api_impl";
|
|
4
|
+
import * as APIExports from "./ordering_api";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// More complex fast food ordering example that uses chat history.
|
|
10
|
+
// Fast food ordering example.
|
|
11
|
+
(async () => {
|
|
12
|
+
const api = new OrderingAPI();
|
|
13
|
+
|
|
14
|
+
const aimyapi = await AIMyAPI.createWithAPI({
|
|
15
|
+
apiObject: api,
|
|
16
|
+
apiGlobalName: "orderingApi", // Should match whatever you declared as your global in your ordering api.
|
|
17
|
+
apiExports: APIExports,
|
|
18
|
+
apiDefFilePath: path.join(__dirname, "./ordering_api.ts"),
|
|
19
|
+
apiDocsPath: path.join(__dirname, "./ordering_api.md"),
|
|
20
|
+
debug: false,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
async function runQuery(query:string) {
|
|
24
|
+
console.log(`Query: ${query}`)
|
|
25
|
+
|
|
26
|
+
// generate the code for this query
|
|
27
|
+
const code = await aimyapi.generateCode(query, api._getHistory());
|
|
28
|
+
|
|
29
|
+
api._addMessageToHistory({
|
|
30
|
+
content: query,
|
|
31
|
+
role: "user",
|
|
32
|
+
name: "user",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
api._addMessageToHistory({
|
|
36
|
+
content: '```\n' + code + '\n```',
|
|
37
|
+
role: "assistant",
|
|
38
|
+
name: "assistant",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// run the code in the sandbox
|
|
42
|
+
await aimyapi.runCode(code);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await runQuery("How's the burger here?");
|
|
46
|
+
await runQuery("I'd like a plain hamburger and a large fries, a pizza with anchovies and a cola. I'd also like a cheese burger with bacon and avocado.");
|
|
47
|
+
await runQuery("I changed my mind, instead of anchovies, can I get a large gluten free pizza with pineapple instead.");
|
|
48
|
+
await runQuery("email me the total at myemail@test.com and complete the order");
|
|
49
|
+
|
|
50
|
+
})();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
|
|
2
|
+
import AIMyAPI from "../lib";
|
|
3
|
+
import { OrderingAPI } from "./ordering_api_impl";
|
|
4
|
+
import * as APIExports from "./ordering_api";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
|
|
9
|
+
function getInput(query): Promise<string> {
|
|
10
|
+
const rl = readline.createInterface({
|
|
11
|
+
input: process.stdin,
|
|
12
|
+
output: process.stdout,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return new Promise(resolve => rl.question(query, ans => {
|
|
16
|
+
rl.close();
|
|
17
|
+
resolve(ans);
|
|
18
|
+
}))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// More complex fast food ordering example that uses chat history.
|
|
22
|
+
// Fast food ordering example.
|
|
23
|
+
// Interactive version
|
|
24
|
+
(async () => {
|
|
25
|
+
const api = new OrderingAPI();
|
|
26
|
+
|
|
27
|
+
const aimyapi = await AIMyAPI.createWithAPI({
|
|
28
|
+
apiObject: api,
|
|
29
|
+
apiGlobalName: "orderingApi", // Should match whatever you declared as your global in your ordering api.
|
|
30
|
+
apiExports: APIExports,
|
|
31
|
+
apiDefFilePath: path.join(__dirname, "./ordering_api.ts"),
|
|
32
|
+
apiDocsPath: path.join(__dirname, "./ordering_api.md"),
|
|
33
|
+
debug: false,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
async function runQuery(query:string) {
|
|
37
|
+
console.log(`Query: ${query}`)
|
|
38
|
+
|
|
39
|
+
// generate the code for this query
|
|
40
|
+
const code = await aimyapi.generateCode(query, api._getHistory());
|
|
41
|
+
|
|
42
|
+
api._addMessageToHistory({
|
|
43
|
+
content: query,
|
|
44
|
+
role: "user",
|
|
45
|
+
name: "user",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
api._addMessageToHistory({
|
|
49
|
+
content: '```\n' + code + '\n```',
|
|
50
|
+
role: "assistant",
|
|
51
|
+
name: "assistant",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// run the code in the sandbox
|
|
55
|
+
await aimyapi.runCode(code);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log("Welcome to the restaurant. You can ask to hear the menu or order something. What would you like to do?");
|
|
59
|
+
while (!api._isCompleted) {
|
|
60
|
+
const query:string = await getInput("Your query: ");
|
|
61
|
+
await runQuery(query);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
})();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
You are an order taking assistant at a restaurant.
|
|
2
|
+
Your responses should be energetic, positive and polite.
|
|
3
|
+
Help the customer with whatever questions they may have and ring up their orders.
|
|
4
|
+
Do not complete the order until the user says they are finished ordering.
|
|
5
|
+
Your code should check for errors or for cases where items may not be found.
|
|
6
|
+
|
|
7
|
+
Examples of how you should respond:
|
|
8
|
+
|
|
9
|
+
user: How are you today?
|
|
10
|
+
|
|
11
|
+
assistant:
|
|
12
|
+
```
|
|
13
|
+
import * as ApiDefs from './api.ts'
|
|
14
|
+
(async() {
|
|
15
|
+
try {
|
|
16
|
+
orderingApi.respondToUser("I'm great, thanks for asking!");
|
|
17
|
+
} catch(e) {
|
|
18
|
+
console.error(e);
|
|
19
|
+
}
|
|
20
|
+
})();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
user: Add a hamburger to my order
|
|
24
|
+
|
|
25
|
+
assistant:
|
|
26
|
+
```
|
|
27
|
+
import * as ApiDefs from './api.ts'
|
|
28
|
+
(async() {
|
|
29
|
+
try {
|
|
30
|
+
orderingApi.addItemToOrder("Hamburger", [], []);
|
|
31
|
+
orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
|
|
32
|
+
} catch(e) {
|
|
33
|
+
console.error(e);
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
user: I'd like a large pizza with mushrooms
|
|
39
|
+
|
|
40
|
+
assistant:
|
|
41
|
+
```
|
|
42
|
+
import * as ApiDefs from './api.ts'
|
|
43
|
+
(async() {
|
|
44
|
+
try {
|
|
45
|
+
ApiDefs.Menu
|
|
46
|
+
orderingApi.addItemToOrder("Pizza", ["Large"], ["mushrooms"]);
|
|
47
|
+
orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
|
|
48
|
+
} catch(err) {
|
|
49
|
+
orderingApi.respondToUser("Apologies, something went wrong with that request.");
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
user: I'd like a cheese burger
|
|
55
|
+
|
|
56
|
+
assistant:
|
|
57
|
+
```
|
|
58
|
+
import * as ApiDefs from './api.ts'
|
|
59
|
+
(async() {
|
|
60
|
+
try {
|
|
61
|
+
orderingApi.addItemToOrder("Hamburger", [], ["cheese"]);
|
|
62
|
+
orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
|
|
63
|
+
} catch(e) {
|
|
64
|
+
orderingApi.respondToUser("Apologies, something went wrong with that request.");
|
|
65
|
+
console.error(e);
|
|
66
|
+
}
|
|
67
|
+
})();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
assistant: Added Hamburger with id 1
|
|
71
|
+
|
|
72
|
+
user: Add jalapenos to that
|
|
73
|
+
|
|
74
|
+
assistant:
|
|
75
|
+
```
|
|
76
|
+
import * as ApiDefs from './api.ts'
|
|
77
|
+
(async() {
|
|
78
|
+
try {
|
|
79
|
+
const existingItem = orderingApi.getItemInOrder("1");
|
|
80
|
+
|
|
81
|
+
if(existingItem) {
|
|
82
|
+
orderingApi.modifyItemInOrder("1", existingItem.customizations.map(item => item.name), [...existingItem.toppings, "jalapenos"]);
|
|
83
|
+
orderingApi.respondToUser("Ok, I added jalapenos to your Hamburger");
|
|
84
|
+
} else {
|
|
85
|
+
orderingApi.respondToUser("Hmm, I can't find that item.");
|
|
86
|
+
}
|
|
87
|
+
} catch(e) {
|
|
88
|
+
orderingApi.respondToUser("Apologies, something went wrong with that request.");
|
|
89
|
+
console.error(e);
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
user: I want an elephant.
|
|
95
|
+
|
|
96
|
+
assistant:
|
|
97
|
+
```
|
|
98
|
+
import * as ApiDefs from './api.ts'
|
|
99
|
+
(async() {
|
|
100
|
+
try {
|
|
101
|
+
orderingApi.respondToUser("I'm sorry, but that isn't on our menu.");
|
|
102
|
+
} catch(e) {
|
|
103
|
+
console.error(e);
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
```
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
export const API_VERSION="1.0.1";
|
|
2
|
+
|
|
3
|
+
export interface Customization {
|
|
4
|
+
name: string;
|
|
5
|
+
priceAdjustment: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface MenuItemBase {
|
|
9
|
+
orderId?: string;
|
|
10
|
+
name: string;
|
|
11
|
+
price: number;
|
|
12
|
+
description: string;
|
|
13
|
+
category: string;
|
|
14
|
+
tags: string[];
|
|
15
|
+
customizations: Customization[];
|
|
16
|
+
readonly allowedCustomizations: Customization[];
|
|
17
|
+
toppings: string[];
|
|
18
|
+
readonly allowedToppings: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const Menu: MenuItemBase[] = [
|
|
22
|
+
{
|
|
23
|
+
"name": "Pizza",
|
|
24
|
+
"price": 10.99,
|
|
25
|
+
"description": "A classic pizza with your choice of toppings.",
|
|
26
|
+
"category": "Pizza",
|
|
27
|
+
"tags": [
|
|
28
|
+
"cheese",
|
|
29
|
+
"pizza"
|
|
30
|
+
],
|
|
31
|
+
"customizations": [],
|
|
32
|
+
"allowedCustomizations": [
|
|
33
|
+
{
|
|
34
|
+
"name": "Extra Cheese",
|
|
35
|
+
"priceAdjustment": 1.99
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "Extra Sauce",
|
|
39
|
+
"priceAdjustment": 0.99
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "Gluten Free Crust",
|
|
43
|
+
"priceAdjustment": 2.99
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "Large",
|
|
47
|
+
"priceAdjustment": 3.99
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"toppings": [],
|
|
51
|
+
"allowedToppings": [
|
|
52
|
+
"pepperoni",
|
|
53
|
+
"sausage",
|
|
54
|
+
"mushrooms",
|
|
55
|
+
"onions",
|
|
56
|
+
"green peppers",
|
|
57
|
+
"black olives",
|
|
58
|
+
"green olives",
|
|
59
|
+
"anchovies",
|
|
60
|
+
"pineapple",
|
|
61
|
+
"ham",
|
|
62
|
+
"bacon",
|
|
63
|
+
"chicken",
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "Hamburger",
|
|
68
|
+
"price": 8.99,
|
|
69
|
+
"description": "A classic american hamburger with your choice of toppings. Cheese, lettuce, tomato, and onion are included by default. Other toppings available on request.",
|
|
70
|
+
"category": "Burgers",
|
|
71
|
+
"tags": [
|
|
72
|
+
"hamburger",
|
|
73
|
+
"burger"
|
|
74
|
+
],
|
|
75
|
+
"customizations": [],
|
|
76
|
+
"allowedCustomizations": [
|
|
77
|
+
{
|
|
78
|
+
"name": "Special sauce",
|
|
79
|
+
"priceAdjustment": 1.99
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"toppings": [],
|
|
83
|
+
"allowedToppings": [
|
|
84
|
+
"cheese",
|
|
85
|
+
"lettuce",
|
|
86
|
+
"tomato",
|
|
87
|
+
"onion",
|
|
88
|
+
"pickles",
|
|
89
|
+
"bacon",
|
|
90
|
+
"mushrooms",
|
|
91
|
+
"avocado",
|
|
92
|
+
"jalapenos",
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "Fries",
|
|
97
|
+
"price": 2.99,
|
|
98
|
+
"description": "A classic side of fries.",
|
|
99
|
+
"category": "Sides",
|
|
100
|
+
"tags": [
|
|
101
|
+
"fries",
|
|
102
|
+
"french fries"
|
|
103
|
+
],
|
|
104
|
+
"customizations": [],
|
|
105
|
+
"allowedCustomizations": [
|
|
106
|
+
{
|
|
107
|
+
"name": "Large",
|
|
108
|
+
"priceAdjustment": 1.99
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
"toppings": [],
|
|
112
|
+
"allowedToppings": [
|
|
113
|
+
"old bay",
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "Fountain Drink",
|
|
118
|
+
"price": 1.99,
|
|
119
|
+
"description": "A classic fountain drink. Choose from Cola, Diet Cola, Dr. Dazzle, or Mountain Rush.",
|
|
120
|
+
"category": "Drinks",
|
|
121
|
+
"tags": [
|
|
122
|
+
"drink",
|
|
123
|
+
"soda",
|
|
124
|
+
"fountain drink"
|
|
125
|
+
],
|
|
126
|
+
"customizations": [],
|
|
127
|
+
"allowedCustomizations": [
|
|
128
|
+
{
|
|
129
|
+
"name": "Large",
|
|
130
|
+
"priceAdjustment": 0.99
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "Extra Ice",
|
|
134
|
+
"priceAdjustment": 0.99
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
"toppings": [],
|
|
138
|
+
"allowedToppings": []
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
export interface OrderingAPIInterface {
|
|
145
|
+
|
|
146
|
+
sendEmail(to: string, subject: string, body: string): Promise<void>;
|
|
147
|
+
// Sends an email to the specified address with the specified subject and body.
|
|
148
|
+
|
|
149
|
+
getCurrentOrder(): MenuItemBase[];
|
|
150
|
+
// Gets the list of items that the user has added to the order so far.
|
|
151
|
+
|
|
152
|
+
getItemInOrder(itemOrderId: string): MenuItemBase | undefined;
|
|
153
|
+
// Gets the item with the specified id from the order.
|
|
154
|
+
// If the item is not in the order, returns undefined.
|
|
155
|
+
|
|
156
|
+
getCustomizationByName(itemName:string, name: string): Customization | undefined;
|
|
157
|
+
// Gets the customization with the specified name for the specified item.
|
|
158
|
+
// If the item does not have a customization with the specified name, returns undefined.
|
|
159
|
+
|
|
160
|
+
addItemToOrder(itemName:string, customizationNames: string[], toppings: string[]): void;
|
|
161
|
+
// Adds the specified item to the order.
|
|
162
|
+
// when adding an item, you should always create a new object that matches the existing menu item structure. Only include the toppings that the user has specified unless they come by default with the item.
|
|
163
|
+
|
|
164
|
+
removeItemFromOrder(itemOrderId: string): void;
|
|
165
|
+
// Removes the item with the specified id from the order.
|
|
166
|
+
|
|
167
|
+
modifyItemInOrder(itemOrderId: string, customizationNames: string[], toppings: string[]): void;
|
|
168
|
+
// Replace the item in the order with the specified item.
|
|
169
|
+
|
|
170
|
+
getOrderTotal(): number;
|
|
171
|
+
// Gets the total price for the current order
|
|
172
|
+
|
|
173
|
+
completeOrder(): void;
|
|
174
|
+
// Completes the order and sends it to the kitchen.
|
|
175
|
+
|
|
176
|
+
respondToUser(text: string): void;
|
|
177
|
+
// Sends a message to the user.
|
|
178
|
+
|
|
179
|
+
delay(milliseconds: number): Promise<void>;
|
|
180
|
+
// waits for the specified number of milliseconds before resolving the promise.
|
|
181
|
+
|
|
182
|
+
displayItem(item: MenuItemBase): void;
|
|
183
|
+
// Displays the specified item to the user.
|
|
184
|
+
|
|
185
|
+
displayOrder(): void;
|
|
186
|
+
// Displays the current order to the user.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Global object you will use for accessing the APIInterface
|
|
192
|
+
declare global {
|
|
193
|
+
var orderingApi: OrderingAPIInterface;
|
|
194
|
+
}
|