aimyapi 0.1.2 → 0.1.4

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 CHANGED
@@ -152,26 +152,218 @@ The module created by the `createWithAPI` function:
152
152
 
153
153
  #### Methods
154
154
 
155
- - `generateCode(queryText: string, userChatHistory: ChatCompletionRequestMessage[]): Promise<string>`: A function that generates code for the given query text and user chat history.
156
- - `runCode(task: string): Promise<void>`: A function that runs the generated code.
157
- - `processRequest(userQuery: string, context?: object): Promise<string>`: A function that processes a user request.
155
+ - `generateCode(queryText: string, userChatHistory: ChatCompletionRequestMessage[]): Promise<string>`: A function that generates code to be run in the sandbox for the given query text and user chat history.
156
+ - `runCode(task: string): Promise<void>`: A function that runs the generated code in the sandbox.
157
+ - `processRequest(userQuery: string, context?: object): Promise<string>`: A single function that generates and runs code assuming no chat history.
158
158
 
159
159
  ## Examples
160
160
 
161
161
  Download or clone the repo. From the root folder run the following.
162
162
 
163
+
164
+ ### Example 1 - sales database
163
165
  A simple api example where the LLM allows you to ask questions and compute things about a dataset
164
166
  ```
165
167
  npm run example1
166
168
  ```
167
169
 
170
+ ```
171
+ import AIMyAPI from "../lib";
172
+ import { API } from "./sales_api_impl";
173
+ import * as APIExports from "./sales_api";
174
+ import path from "path";
175
+
176
+ // Simpler example using no support for chat history;
177
+
178
+ (async () => {
179
+ const api = new API();
180
+
181
+ const aimyapi = await AIMyAPI.createWithAPI({
182
+ apiObject: api,
183
+ apiGlobalName: "api", // Should match whatever you declared as your global in your api.
184
+ apiExports: APIExports,
185
+ apiDefFilePath: path.join(__dirname, "./sales_api.ts"),
186
+ apiDocsPath: path.join(__dirname, "./sales_api.md"),
187
+ debug: false,
188
+ })
189
+
190
+ console.log("Print 'hello' three times.")
191
+ await aimyapi.processRequest("Print 'hello' three times.");
192
+
193
+ console.log("What was our best month in 2020")
194
+ await aimyapi.processRequest("What was our best month in 2020");
195
+
196
+ console.log("Which business unit had the highest sales in 2020?")
197
+ await aimyapi.processRequest("Which business unit had the highest sales in 2020?");
198
+
199
+ console.log("Compute the total sales for each month in 2020 then email the top 3 to test@email.com")
200
+ await aimyapi.processRequest("Compute the total sales for each month in 2020 then email the top 3 to test@email.com");
201
+ })();
202
+ ```
203
+
204
+ Output:
205
+ ```
206
+ Print 'hello' three times.
207
+ Generate Task: 4.086s
208
+ hello
209
+ hello
210
+ hello
211
+ Run Code: 379.328ms
212
+ What was our best month in 2020
213
+ Generate Task: 11.345s
214
+ Our best month in 2020 was month 8 with 4400 sales.
215
+ Run Code: 119.145ms
216
+ Which business unit had the highest sales in 2020?
217
+ Generate Task: 11.477s
218
+ The business unit with the highest sales in 2020 was Hardware
219
+ Run Code: 124.522ms
220
+ Compute the total sales for each month in 2020 then email the top 3 to test@email.com
221
+ Generate Task: 15.648s
222
+ Sending email to "test@email.com" with subject "Top 3 Sales Months in 2020" and body
223
+ "Top 3 sales months in 2020:
224
+ Month 8: $4400
225
+ Month 7: $4300
226
+ Month 6: $4000"
227
+ Run Code: 1.200s
228
+ ```
229
+
230
+ ### Example 2 - Food ordering bot
231
+
168
232
  A more complex food ordering example which incorporates chat history
169
233
 
170
234
  ```
171
235
  npm run example2
172
236
  ```
173
237
 
174
- Interactive ordering example (same api as example2)
238
+ Code:
239
+ ```
240
+ import AIMyAPI from "../lib";
241
+ import { OrderingAPI } from "./ordering_api_impl";
242
+ import * as APIExports from "./ordering_api";
243
+ import path from "path";
244
+
245
+ // More complex fast food ordering example that uses chat history.
246
+ // Fast food ordering example.
247
+ (async () => {
248
+ const api = new OrderingAPI();
249
+
250
+ const aimyapi = await AIMyAPI.createWithAPI({
251
+ apiObject: api,
252
+ apiGlobalName: "orderingApi", // Should match whatever you declared as your global in your ordering api.
253
+ apiExports: APIExports,
254
+ apiDefFilePath: path.join(__dirname, "./ordering_api.ts"),
255
+ apiDocsPath: path.join(__dirname, "./ordering_api.md"),
256
+ debug: false,
257
+ })
258
+
259
+ async function runQuery(query:string) {
260
+ console.log(`Query: ${query}`)
261
+
262
+ // generate the code for this query
263
+ const code = await aimyapi.generateCode(query, api._getHistory());
264
+
265
+ api._addMessageToHistory({
266
+ content: query,
267
+ role: "user",
268
+ name: "user",
269
+ });
270
+
271
+ api._addMessageToHistory({
272
+ content: '```\n' + code + '\n```',
273
+ role: "assistant",
274
+ name: "assistant",
275
+ });
276
+
277
+ // run the code in the sandbox
278
+ await aimyapi.runCode(code);
279
+ }
280
+
281
+ await runQuery("How's the burger here?");
282
+ 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.");
283
+ await runQuery("I changed my mind, instead of anchovies, can I get a large gluten free pizza with pineapple instead.");
284
+ await runQuery("email me the total at myemail@test.com and complete the order");
285
+
286
+ })();
287
+ ```
288
+
289
+ Output:
290
+ ```
291
+ Query: How's the burger here?
292
+ Our Hamburger is delicious! It comes with cheese, lettuce, tomato, and onion by default, but you can customize it with any of our toppings.
293
+ Query: I'd like a plain hamburger (no cheese) and a large fries, a pizza with anchovies and a cola. I'd also like a cheese burger with bacon and avocado.
294
+ added #0 Hamburger... $8.99
295
+ lettuce
296
+ tomato
297
+ onion
298
+
299
+ Ok, I added a plain hamburger. What else would you like?
300
+ added #1 Fries... $2.99
301
+ Large... $1.99
302
+
303
+ Ok, I added large fries. What else would you like?
304
+ added #2 Pizza... $10.99
305
+ anchovies
306
+
307
+ Ok, I added a pizza with anchovies. What else would you like?
308
+ added #3 Fountain Drink... $1.99
309
+ Large... $0.99
310
+
311
+ Ok, I added a cola. What else would you like?
312
+ added #4 Hamburger... $8.99
313
+ cheese
314
+ lettuce
315
+ tomato
316
+ onion
317
+ cheese
318
+ bacon
319
+ avocado
320
+
321
+ Ok, I added a cheese burger with bacon and avocado. Is there anything else I can help you with?
322
+ Query: I changed my mind, instead of anchovies, can I get a large gluten free pizza with pineapple instead.
323
+ Removed item 2
324
+ added #5 Pizza... $10.99
325
+ pineapple
326
+ Gluten Free Crust... $2.99
327
+
328
+ Ok, I added a large gluten free pizza with pineapple. Is there anything else I can help you with?
329
+ Query: email me the total at myemail@test.com and complete the order
330
+ Sending email to "myemail@test.com" with subject "Order Total" and body
331
+ "Your order total is $39.92."
332
+ ----
333
+
334
+ Displaying order:
335
+ #0 Hamburger... $8.99
336
+ lettuce
337
+ tomato
338
+ onion
339
+
340
+ #1 Fries... $2.99
341
+ Large... $1.99
342
+
343
+ #3 Fountain Drink... $1.99
344
+ Large... $0.99
345
+
346
+ #4 Hamburger... $8.99
347
+ cheese
348
+ lettuce
349
+ tomato
350
+ onion
351
+ cheese
352
+ bacon
353
+ avocado
354
+
355
+ #5 Pizza... $10.99
356
+ pineapple
357
+ Gluten Free Crust... $2.99
358
+
359
+ -- Total: $39.92
360
+ Order completed!
361
+ Your order has been completed. Thank you for choosing our restaurant!
362
+ ```
363
+
364
+ # Example 3 - interactive food ordering
365
+
366
+ Interactive ordering example (same api as example2). You can type your own orders on the command line.
175
367
 
176
368
  ```
177
369
  npm run example3
@@ -19,7 +19,7 @@ export interface CreateWithAPIExports {
19
19
  export interface AIMyAPIExports {
20
20
  createWithAPI: (options: AIMyAPIOptions) => Promise<CreateWithAPIExports>;
21
21
  createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
22
- generateTask: (queryText: string, userChatHistory: any[], createTaskPrompt: string, apiPath: string) => Promise<string>;
22
+ generateCode: (queryText: string, userChatHistory: ChatCompletionRequestMessage[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<string>;
23
23
  createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
24
24
  }
25
25
  declare const aimyapi: AIMyAPIExports;
@@ -29,12 +29,24 @@ function createBasePrompt(apiFilePath, documentationPath) {
29
29
  return createTaskPrompt;
30
30
  }
31
31
  exports.createBasePrompt = createBasePrompt;
32
- // userChatHistory is not currently used but could be in the future.
32
+ // FIXME: add an options parameter and allow specifying the token limit
33
33
  const generateCode = async function (queryText, userChatHistory, createTaskPrompt, apiPath, debug = false) {
34
34
  if (!queryText)
35
35
  return;
36
36
  let generatedCode = '';
37
37
  const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
38
+ const messages = [
39
+ {
40
+ role: "system",
41
+ content: prompt,
42
+ },
43
+ ...userChatHistory,
44
+ {
45
+ role: "user",
46
+ content: `${queryText}`,
47
+ name: "user"
48
+ }
49
+ ];
38
50
  // TODO: I should switch this back to gpt3.5 turbo since it's cheaper
39
51
  try {
40
52
  // const task = await openai.createCompletion(
@@ -47,20 +59,9 @@ const generateCode = async function (queryText, userChatHistory, createTaskPromp
47
59
  // );
48
60
  const results = await openai.createChatCompletion({
49
61
  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
+ messages: messages,
62
63
  temperature: 0.1,
63
- max_tokens: 800,
64
+ max_tokens: 700,
64
65
  });
65
66
  if (debug)
66
67
  console.log(results.data.usage);
@@ -73,11 +74,12 @@ const generateCode = async function (queryText, userChatHistory, createTaskPromp
73
74
  if (codeStart === -1 || codeEnd === -1 || codeStart === codeEnd)
74
75
  return '';
75
76
  generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
76
- generatedCode = `// Query=${queryText}\n` + generatedCode.replace("./api.ts", apiPath);
77
+ generatedCode = generatedCode.replace("./api.ts", apiPath);
77
78
  return generatedCode;
78
79
  }
79
80
  catch (err) {
80
81
  console.error(err);
82
+ console.log("Prompt", messages);
81
83
  return '';
82
84
  }
83
85
  };
@@ -173,7 +175,7 @@ const aimyapi = {
173
175
  createWithAPI,
174
176
  // functions for customized usage
175
177
  createBasePrompt,
176
- generateTask: exports.generateCode,
178
+ generateCode: exports.generateCode,
177
179
  createSandbox: sandbox_1.default,
178
180
  };
179
181
  exports.default = aimyapi;
@@ -121,7 +121,7 @@ async function createSandbox(QuickJS, requireLookup = {}, globals = {}, debug =
121
121
  try {
122
122
  const compiled = tsCompile(task);
123
123
  if (!compiled || compiled.length === 0) {
124
- console.log("Could not compile");
124
+ console.error("Could not compile", task);
125
125
  return false;
126
126
  }
127
127
  // View compiled typescript code for debugging
@@ -1,10 +1,8 @@
1
-
2
1
  import AIMyAPI from "../lib";
3
2
  import { API } from "./sales_api_impl";
4
3
  import * as APIExports from "./sales_api";
5
4
  import path from "path";
6
5
 
7
-
8
6
  // Simpler example using no support for chat history;
9
7
 
10
8
  (async () => {
@@ -1,24 +1,22 @@
1
-
2
1
  import AIMyAPI from "../lib";
3
2
  import { OrderingAPI } from "./ordering_api_impl";
4
3
  import * as APIExports from "./ordering_api";
5
4
  import path from "path";
6
5
 
7
-
8
-
9
6
  // More complex fast food ordering example that uses chat history.
10
7
  // Fast food ordering example.
11
8
  (async () => {
12
9
  const api = new OrderingAPI();
13
10
 
14
- const aimyapi = await AIMyAPI.createWithAPI({
11
+ const options = {
15
12
  apiObject: api,
16
13
  apiGlobalName: "orderingApi", // Should match whatever you declared as your global in your ordering api.
17
14
  apiExports: APIExports,
18
15
  apiDefFilePath: path.join(__dirname, "./ordering_api.ts"),
19
16
  apiDocsPath: path.join(__dirname, "./ordering_api.md"),
20
17
  debug: false,
21
- })
18
+ };
19
+ const aimyapi = await AIMyAPI.createWithAPI(options)
22
20
 
23
21
  async function runQuery(query:string) {
24
22
  console.log(`Query: ${query}`)
@@ -33,7 +31,7 @@ import path from "path";
33
31
  });
34
32
 
35
33
  api._addMessageToHistory({
36
- content: '```\n' + code + '\n```',
34
+ content: '```\n' + code.replace(options.apiDefFilePath, "./api.ts") + '\n```',
37
35
  role: "assistant",
38
36
  name: "assistant",
39
37
  });
@@ -43,7 +41,7 @@ import path from "path";
43
41
  }
44
42
 
45
43
  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.");
44
+ await runQuery("I'd like a plain hamburger (no cheese) and a large fries, a pizza with anchovies and a cola. I'd also like a cheese burger with bacon and avocado.");
47
45
  await runQuery("I changed my mind, instead of anchovies, can I get a large gluten free pizza with pineapple instead.");
48
46
  await runQuery("email me the total at myemail@test.com and complete the order");
49
47
 
@@ -20,14 +20,20 @@ import * as ApiDefs from './api.ts'
20
20
  })();
21
21
  ```
22
22
 
23
- user: Add a hamburger to my order
23
+ user: Add a hamburger with no cheese to my order
24
24
 
25
25
  assistant:
26
26
  ```
27
27
  import * as ApiDefs from './api.ts'
28
28
  (async() {
29
29
  try {
30
- orderingApi.addItemToOrder("Hamburger", [], []);
30
+ const itemName = "Hamburger";
31
+ const item = ApiDefs.Menu.find((item) => item.name === itemName);
32
+ if (!item) {
33
+ throw new Error(`Item with name "${itemName}" not found`);
34
+ }
35
+
36
+ orderingApi.addItemToOrder(itemName, undefined, item.toppings.filter( topping => topping.name != "cheese") );
31
37
  orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
32
38
  } catch(e) {
33
39
  console.error(e);
@@ -35,6 +41,8 @@ import * as ApiDefs from './api.ts'
35
41
  })();
36
42
  ```
37
43
 
44
+ assistant: Added Hamburger with id 1
45
+
38
46
  user: I'd like a large pizza with mushrooms
39
47
 
40
48
  assistant:
@@ -42,7 +50,6 @@ assistant:
42
50
  import * as ApiDefs from './api.ts'
43
51
  (async() {
44
52
  try {
45
- ApiDefs.Menu
46
53
  orderingApi.addItemToOrder("Pizza", ["Large"], ["mushrooms"]);
47
54
  orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
48
55
  } catch(err) {
@@ -51,23 +58,28 @@ import * as ApiDefs from './api.ts'
51
58
  })();
52
59
  ```
53
60
 
54
- user: I'd like a cheese burger
61
+ user: Add a hamburger with bacon
55
62
 
56
- assistant:
63
+ assistant:
57
64
  ```
58
65
  import * as ApiDefs from './api.ts'
59
66
  (async() {
60
67
  try {
61
- orderingApi.addItemToOrder("Hamburger", [], ["cheese"]);
62
- orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
68
+ const itemName = "Hamburger";
69
+ const item = ApiDefs.Menu.find((item) => item.name === itemName);
70
+ if (!item) {
71
+ throw new Error(`Item with name "${itemName}" not found`);
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?");
63
76
  } catch(e) {
64
- orderingApi.respondToUser("Apologies, something went wrong with that request.");
65
77
  console.error(e);
66
78
  }
67
79
  })();
68
80
  ```
69
81
 
70
- assistant: Added Hamburger with id 1
82
+ assistant: Added Hamburger with id 2
71
83
 
72
84
  user: Add jalapenos to that
73
85
 
@@ -76,10 +88,10 @@ assistant:
76
88
  import * as ApiDefs from './api.ts'
77
89
  (async() {
78
90
  try {
79
- const existingItem = orderingApi.getItemInOrder("1");
91
+ const existingItem = orderingApi.getItemInOrder("2");
80
92
 
81
93
  if(existingItem) {
82
- orderingApi.modifyItemInOrder("1", existingItem.customizations.map(item => item.name), [...existingItem.toppings, "jalapenos"]);
94
+ orderingApi.modifyItemInOrder("2", existingItem.customizations.map(item => item.name), [...existingItem.toppings, "jalapenos"]);
83
95
  orderingApi.respondToUser("Ok, I added jalapenos to your Hamburger");
84
96
  } else {
85
97
  orderingApi.respondToUser("Hmm, I can't find that item.");
@@ -66,20 +66,15 @@ export const Menu: MenuItemBase[] = [
66
66
  {
67
67
  "name": "Hamburger",
68
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.",
69
+ "description": "A classic american hamburger with your choice of toppings. Cheese, lettuce, tomato, and onion toppings are included by default. Other toppings available on request.",
70
70
  "category": "Burgers",
71
71
  "tags": [
72
72
  "hamburger",
73
73
  "burger"
74
74
  ],
75
75
  "customizations": [],
76
- "allowedCustomizations": [
77
- {
78
- "name": "Special sauce",
79
- "priceAdjustment": 1.99
80
- }
81
- ],
82
- "toppings": [],
76
+ "allowedCustomizations": [],
77
+ "toppings": [ "cheese", "lettuce", "tomato", "onion"],
83
78
  "allowedToppings": [
84
79
  "cheese",
85
80
  "lettuce",
@@ -116,7 +111,7 @@ export const Menu: MenuItemBase[] = [
116
111
  {
117
112
  "name": "Fountain Drink",
118
113
  "price": 1.99,
119
- "description": "A classic fountain drink. Choose from Cola, Diet Cola, Dr. Dazzle, or Mountain Rush.",
114
+ "description": "A classic fountain drink. Choose from the following sodas Cola, Diet Cola, Dr. Dazzle, or Mountain Rush. Large size available on request.",
120
115
  "category": "Drinks",
121
116
  "tags": [
122
117
  "drink",
@@ -157,9 +152,9 @@ export interface OrderingAPIInterface {
157
152
  // Gets the customization with the specified name for the specified item.
158
153
  // If the item does not have a customization with the specified name, returns undefined.
159
154
 
160
- addItemToOrder(itemName:string, customizationNames: string[], toppings: string[]): void;
155
+ addItemToOrder(itemName:string, customizationNames: string[] | undefined, toppings: string[] | undefined): void;
161
156
  // 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.
157
+ // leave customizationNames and toppings undefined if you want to use the default values for the item.
163
158
 
164
159
  removeItemFromOrder(itemOrderId: string): void;
165
160
  // Removes the item with the specified id from the order.
@@ -179,8 +174,9 @@ export interface OrderingAPIInterface {
179
174
  delay(milliseconds: number): Promise<void>;
180
175
  // waits for the specified number of milliseconds before resolving the promise.
181
176
 
182
- displayItem(item: MenuItemBase): void;
177
+ displayItem(item: MenuItemBase, justAdded:boolean): void;
183
178
  // Displays the specified item to the user.
179
+ // If justAdded is true, the item will be displayed as a new item in the order.
184
180
 
185
181
  displayOrder(): void;
186
182
  // Displays the current order to the user.
@@ -26,10 +26,7 @@ export class OrderingAPI implements OrderingAPIInterface {
26
26
 
27
27
  respondToUser(text: string): void {
28
28
  console.log(text);
29
- this._history.push({
30
- role: "assistant",
31
- content: "Response output: " + text,
32
- });
29
+
33
30
  }
34
31
 
35
32
  delay(milliseconds: number): Promise<void> {
@@ -61,33 +58,38 @@ export class OrderingAPI implements OrderingAPIInterface {
61
58
 
62
59
  addItemToOrder(
63
60
  itemName: string,
64
- customizationNames: string[],
65
- toppings: string[]
61
+ customizationNames: string[] | undefined,
62
+ toppings: string[] | undefined
66
63
  ) {
67
64
  const item = Menu.find((item) => item.name === itemName);
68
65
  if (!item) {
69
66
  throw new Error(`Item with name "${itemName}" not found`);
70
67
  }
71
68
 
72
- const customizations = customizationNames
69
+ const customizations = customizationNames ? customizationNames
73
70
  .map((customizationName) => {
74
71
  return this.getCustomizationByName(itemName, customizationName);
75
72
  })
76
73
  .filter(
77
74
  (customization) => customization !== undefined
78
- ) as Customization[];
75
+ ) as Customization[] : [...item.customizations];
79
76
 
80
77
  const newItem = {
81
78
  ...item,
82
79
  customizations,
83
- toppings: toppings,
80
+ toppings: toppings ? toppings : [...item.toppings],
84
81
  orderId: "" + this._lastOrderIdNumber++,
85
82
  };
86
83
 
87
84
  this._order.push(newItem);
88
85
 
89
- this.respondToUser(`Added ${itemName} with id ${newItem.orderId}`);
90
- this.displayItem(newItem);
86
+ //this.respondToUser(`Added ${itemName} with id ${newItem.orderId}`);
87
+
88
+ this._history.push({
89
+ role: "user",
90
+ content: `I see you have added added ${itemName} with id ${newItem.orderId}`,
91
+ });
92
+ this.displayItem(newItem, true);
91
93
  }
92
94
 
93
95
  getItemInOrder(itemOrderId: string): MenuItemBase {
@@ -102,6 +104,10 @@ export class OrderingAPI implements OrderingAPIInterface {
102
104
  removeItemFromOrder(itemOrderId: string) {
103
105
  this._order = this._order.filter((item) => item.orderId !== itemOrderId);
104
106
 
107
+ this._history.push({
108
+ role: "user",
109
+ content: `I see you have removed item ${itemOrderId}`,
110
+ });
105
111
  this.respondToUser(`Removed item ${itemOrderId}`);
106
112
  }
107
113
 
@@ -132,6 +138,10 @@ export class OrderingAPI implements OrderingAPIInterface {
132
138
  throw new Error(`Item with id #"${itemOrderId}" not found in order`);
133
139
  }
134
140
 
141
+ this._history.push({
142
+ role: "user",
143
+ content: `I see you have modified item ${itemOrderId}`,
144
+ });
135
145
  this.respondToUser(`Modified item ${itemOrderId}`);
136
146
  }
137
147
 
@@ -160,20 +170,19 @@ export class OrderingAPI implements OrderingAPIInterface {
160
170
  this._isCompleted = true;
161
171
  }
162
172
 
163
- displayItem(item: MenuItemBase) {
164
- this.respondToUser(
165
- `\t#${item.orderId || ""} ${item.name}...\t\t$${item.price.toFixed(2)}`
166
- );
173
+ displayItem(item: MenuItemBase, justAdded: boolean = false) {
174
+ let output = "";
175
+
176
+ output += `\t${justAdded ? "added " : ""}#${item.orderId || ""} ${item.name}...\t\t$${item.price.toFixed(2)}\n`;
167
177
  item.toppings.forEach((topping) => {
168
- this.respondToUser(`\t\t${topping}`);
178
+ output += `\t\t${topping}\n`;
169
179
  });
170
180
  item.customizations.forEach((customization) => {
171
- this.respondToUser(
172
- `\t\t${customization.name}...\t$${customization.priceAdjustment.toFixed(
173
- 2
174
- )}`
175
- );
181
+ output += `\t\t${customization.name}...\t$${customization.priceAdjustment.toFixed(2)}\n`;
176
182
  });
183
+
184
+
185
+ this.respondToUser(output)
177
186
  }
178
187
 
179
188
  displayOrder() {