aimyapi 0.1.15 → 0.2.1

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/dist/index.cjs CHANGED
@@ -340,16 +340,38 @@ const openai = new openai$1.OpenAI({
340
340
  apiKey: process.env.OPENAI_API_KEY
341
341
  // This is also the default, can be omitted
342
342
  });
343
+ const CODE_START = `\`\`\`
344
+ import * as ApiDefs from 'api.ts'
345
+
346
+ (async() {
347
+ try {`;
348
+ const CODE_END = ` } catch(err) {
349
+ console.error(err);
350
+ }
351
+ })();
352
+ \`\`\``;
353
+ function indentString(str, numTabs) {
354
+ const tabs = " ".repeat(numTabs);
355
+ return str.split("\n").map((line) => tabs + line).join("\n");
356
+ }
357
+ function replaceCodeBlocks(text) {
358
+ const codeBlockRegex = /```[\s\S]*?```/g;
359
+ return text.replace(codeBlockRegex, (match) => {
360
+ const code = match.slice(3, -3).trim();
361
+ return `${CODE_START}
362
+ ${indentString(code, 2)}
363
+ ${CODE_END}`;
364
+ });
365
+ }
343
366
  function createBasePrompt(apiFilePath, documentationPath) {
344
367
  const apiText = fs.readFileSync(apiFilePath, "utf8");
345
368
  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);
369
+ const createTaskPrompt = fs.readFileSync(path.join(__dirname, "../prompts/create-task-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", replaceCodeBlocks(documentationText)).replace("{{API}}", apiText);
347
370
  return createTaskPrompt;
348
371
  }
349
- const generateCode = async function(queryText, userChatHistory, createTaskPrompt, apiPath, debug = false, model = "gpt-4o") {
372
+ const generateCode = async function(queryText, userChatHistory, createTaskPrompt, debug = false, model = "gpt-4o-mini") {
350
373
  if (!queryText)
351
374
  return { code: "", loggableCode: "" };
352
- let generatedCode = "";
353
375
  const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
354
376
  const messages = [
355
377
  {
@@ -359,8 +381,7 @@ const generateCode = async function(queryText, userChatHistory, createTaskPrompt
359
381
  ...userChatHistory,
360
382
  {
361
383
  role: "user",
362
- content: `${queryText}.
363
- Respond only with code enclosed in \`\`\`.`,
384
+ content: `${queryText}. Respond with json`,
364
385
  name: "user"
365
386
  }
366
387
  ];
@@ -370,7 +391,23 @@ Respond only with code enclosed in \`\`\`.`,
370
391
  model,
371
392
  messages,
372
393
  temperature: 0,
373
- max_tokens: 700
394
+ max_tokens: 2e3,
395
+ response_format: {
396
+ json_schema: {
397
+ name: "codeResponse",
398
+ description: "The code generated by the AI",
399
+ schema: {
400
+ type: "object",
401
+ properties: {
402
+ yourCode: {
403
+ type: "string",
404
+ description: "The code generated by the AI"
405
+ }
406
+ }
407
+ }
408
+ },
409
+ type: "json_schema"
410
+ }
374
411
  }
375
412
  );
376
413
  if (debug)
@@ -378,21 +415,14 @@ Respond only with code enclosed in \`\`\`.`,
378
415
  const response = results.choices[0].message.content;
379
416
  if (debug)
380
417
  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 };
418
+ try {
419
+ const json = JSON.parse(response);
420
+ const code = json.yourCode.replaceAll("```", "");
421
+ return { code, loggableCode: code };
422
+ } catch (err) {
423
+ console.error("Error parsing response", err);
424
+ return { code: "", loggableCode: "" };
385
425
  }
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
426
  } catch (err) {
397
427
  console.error(err);
398
428
  return { code: "", loggableCode: "" };
@@ -405,7 +435,7 @@ async function createWithAPI(options) {
405
435
  apiGlobals: {},
406
436
  apiWhitelist: Object.getOwnPropertyNames(Object.getPrototypeOf(options.apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_")),
407
437
  debug: false,
408
- model: "gpt-4o",
438
+ model: "gpt-4o-mini",
409
439
  ...options
410
440
  };
411
441
  if (!options.apiObject || !options.apiDefFilePath) {
@@ -418,7 +448,7 @@ async function createWithAPI(options) {
418
448
  generateCode: async function(queryText, userChatHistory, currentContext = void 0) {
419
449
  if (!queryText)
420
450
  return { code: "", loggableCode: "" };
421
- return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug, model);
451
+ return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), debug, model);
422
452
  },
423
453
  runCode: async function(generatedCode) {
424
454
  if (!QuickJS) {
@@ -445,7 +475,7 @@ async function createWithAPI(options) {
445
475
  if (debug) {
446
476
  console.log("Running Code:\n", generatedCode);
447
477
  }
448
- const res = await runTask(generatedCode);
478
+ const res = await runTask(generatedCode.replace("'api.ts'", `'${options.apiDefFilePath}'`));
449
479
  if (!res) {
450
480
  console.error("Task unsuccessful");
451
481
  }
@@ -469,10 +499,10 @@ async function createWithAPI(options) {
469
499
  console.log("Query:", userQuery);
470
500
  }
471
501
  console.time("Generate Task");
472
- const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
502
+ const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""));
473
503
  console.timeEnd("Generate Task");
474
504
  console.time("Run Code");
475
- await this.runCode(generatedCode.code);
505
+ await this.runCode(generatedCode.code.replace("'api.ts'", `'${options.apiDefFilePath}'`));
476
506
  console.timeEnd("Run Code");
477
507
  return generatedCode;
478
508
  }
package/dist/index.d.cts CHANGED
@@ -7,7 +7,7 @@ interface GenerateCodeResult {
7
7
  loggableCode: string;
8
8
  rawResponse?: string;
9
9
  }
10
- declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
10
+ declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
11
11
  interface AIMyAPIOptions {
12
12
  apiObject: object;
13
13
  apiExports: object;
@@ -28,7 +28,7 @@ interface AIMyAPIInstance {
28
28
  interface AIMyAPIModuleExports {
29
29
  createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
30
30
  createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
31
- generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
31
+ generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug: boolean) => Promise<GenerateCodeResult>;
32
32
  createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
33
33
  }
34
34
  declare const AIMyAPI: AIMyAPIModuleExports;
package/dist/index.d.mts CHANGED
@@ -7,7 +7,7 @@ interface GenerateCodeResult {
7
7
  loggableCode: string;
8
8
  rawResponse?: string;
9
9
  }
10
- declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
10
+ declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
11
11
  interface AIMyAPIOptions {
12
12
  apiObject: object;
13
13
  apiExports: object;
@@ -28,7 +28,7 @@ interface AIMyAPIInstance {
28
28
  interface AIMyAPIModuleExports {
29
29
  createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
30
30
  createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
31
- generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
31
+ generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug: boolean) => Promise<GenerateCodeResult>;
32
32
  createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
33
33
  }
34
34
  declare const AIMyAPI: AIMyAPIModuleExports;
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ interface GenerateCodeResult {
7
7
  loggableCode: string;
8
8
  rawResponse?: string;
9
9
  }
10
- declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
10
+ declare const generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug?: boolean, model?: string) => Promise<GenerateCodeResult>;
11
11
  interface AIMyAPIOptions {
12
12
  apiObject: object;
13
13
  apiExports: object;
@@ -28,7 +28,7 @@ interface AIMyAPIInstance {
28
28
  interface AIMyAPIModuleExports {
29
29
  createWithAPI: (options: AIMyAPIOptions) => Promise<AIMyAPIInstance>;
30
30
  createBasePrompt: (apiFilePath: string, documentationPath: string) => string;
31
- generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, apiPath: string, debug: boolean) => Promise<GenerateCodeResult>;
31
+ generateCode: (queryText: string, userChatHistory: ChatCompletionMessageParam[], createTaskPrompt: string, debug: boolean) => Promise<GenerateCodeResult>;
32
32
  createSandbox: (QuickJS: QuickJSWASMModule, globals: any) => Promise<any>;
33
33
  }
34
34
  declare const AIMyAPI: AIMyAPIModuleExports;
package/dist/index.js CHANGED
@@ -340,16 +340,38 @@ const openai = new openai$1.OpenAI({
340
340
  apiKey: process.env.OPENAI_API_KEY
341
341
  // This is also the default, can be omitted
342
342
  });
343
+ const CODE_START = `\`\`\`
344
+ import * as ApiDefs from 'api.ts'
345
+
346
+ (async() {
347
+ try {`;
348
+ const CODE_END = ` } catch(err) {
349
+ console.error(err);
350
+ }
351
+ })();
352
+ \`\`\``;
353
+ function indentString(str, numTabs) {
354
+ const tabs = " ".repeat(numTabs);
355
+ return str.split("\n").map((line) => tabs + line).join("\n");
356
+ }
357
+ function replaceCodeBlocks(text) {
358
+ const codeBlockRegex = /```[\s\S]*?```/g;
359
+ return text.replace(codeBlockRegex, (match) => {
360
+ const code = match.slice(3, -3).trim();
361
+ return `${CODE_START}
362
+ ${indentString(code, 2)}
363
+ ${CODE_END}`;
364
+ });
365
+ }
343
366
  function createBasePrompt(apiFilePath, documentationPath) {
344
367
  const apiText = fs.readFileSync(apiFilePath, "utf8");
345
368
  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);
369
+ const createTaskPrompt = fs.readFileSync(path.join(__dirname, "../prompts/create-task-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", replaceCodeBlocks(documentationText)).replace("{{API}}", apiText);
347
370
  return createTaskPrompt;
348
371
  }
349
- const generateCode = async function(queryText, userChatHistory, createTaskPrompt, apiPath, debug = false, model = "gpt-4o") {
372
+ const generateCode = async function(queryText, userChatHistory, createTaskPrompt, debug = false, model = "gpt-4o-mini") {
350
373
  if (!queryText)
351
374
  return { code: "", loggableCode: "" };
352
- let generatedCode = "";
353
375
  const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
354
376
  const messages = [
355
377
  {
@@ -359,8 +381,7 @@ const generateCode = async function(queryText, userChatHistory, createTaskPrompt
359
381
  ...userChatHistory,
360
382
  {
361
383
  role: "user",
362
- content: `${queryText}.
363
- Respond only with code enclosed in \`\`\`.`,
384
+ content: `${queryText}. Respond with json`,
364
385
  name: "user"
365
386
  }
366
387
  ];
@@ -370,7 +391,23 @@ Respond only with code enclosed in \`\`\`.`,
370
391
  model,
371
392
  messages,
372
393
  temperature: 0,
373
- max_tokens: 700
394
+ max_tokens: 2e3,
395
+ response_format: {
396
+ json_schema: {
397
+ name: "codeResponse",
398
+ description: "The code generated by the AI",
399
+ schema: {
400
+ type: "object",
401
+ properties: {
402
+ yourCode: {
403
+ type: "string",
404
+ description: "The code generated by the AI"
405
+ }
406
+ }
407
+ }
408
+ },
409
+ type: "json_schema"
410
+ }
374
411
  }
375
412
  );
376
413
  if (debug)
@@ -378,21 +415,14 @@ Respond only with code enclosed in \`\`\`.`,
378
415
  const response = results.choices[0].message.content;
379
416
  if (debug)
380
417
  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 };
418
+ try {
419
+ const json = JSON.parse(response);
420
+ const code = json.yourCode.replaceAll("```", "");
421
+ return { code, loggableCode: code };
422
+ } catch (err) {
423
+ console.error("Error parsing response", err);
424
+ return { code: "", loggableCode: "" };
385
425
  }
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
426
  } catch (err) {
397
427
  console.error(err);
398
428
  return { code: "", loggableCode: "" };
@@ -405,7 +435,7 @@ async function createWithAPI(options) {
405
435
  apiGlobals: {},
406
436
  apiWhitelist: Object.getOwnPropertyNames(Object.getPrototypeOf(options.apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_")),
407
437
  debug: false,
408
- model: "gpt-4o",
438
+ model: "gpt-4o-mini",
409
439
  ...options
410
440
  };
411
441
  if (!options.apiObject || !options.apiDefFilePath) {
@@ -418,7 +448,7 @@ async function createWithAPI(options) {
418
448
  generateCode: async function(queryText, userChatHistory, currentContext = void 0) {
419
449
  if (!queryText)
420
450
  return { code: "", loggableCode: "" };
421
- return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug, model);
451
+ return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), debug, model);
422
452
  },
423
453
  runCode: async function(generatedCode) {
424
454
  if (!QuickJS) {
@@ -445,7 +475,7 @@ async function createWithAPI(options) {
445
475
  if (debug) {
446
476
  console.log("Running Code:\n", generatedCode);
447
477
  }
448
- const res = await runTask(generatedCode);
478
+ const res = await runTask(generatedCode.replace("'api.ts'", `'${options.apiDefFilePath}'`));
449
479
  if (!res) {
450
480
  console.error("Task unsuccessful");
451
481
  }
@@ -469,10 +499,10 @@ async function createWithAPI(options) {
469
499
  console.log("Query:", userQuery);
470
500
  }
471
501
  console.time("Generate Task");
472
- const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
502
+ const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""));
473
503
  console.timeEnd("Generate Task");
474
504
  console.time("Run Code");
475
- await this.runCode(generatedCode.code);
505
+ await this.runCode(generatedCode.code.replace("'api.ts'", `'${options.apiDefFilePath}'`));
476
506
  console.timeEnd("Run Code");
477
507
  return generatedCode;
478
508
  }
package/dist/index.mjs CHANGED
@@ -318,16 +318,38 @@ const openai = new OpenAI({
318
318
  apiKey: process.env.OPENAI_API_KEY
319
319
  // This is also the default, can be omitted
320
320
  });
321
+ const CODE_START = `\`\`\`
322
+ import * as ApiDefs from 'api.ts'
323
+
324
+ (async() {
325
+ try {`;
326
+ const CODE_END = ` } catch(err) {
327
+ console.error(err);
328
+ }
329
+ })();
330
+ \`\`\``;
331
+ function indentString(str, numTabs) {
332
+ const tabs = " ".repeat(numTabs);
333
+ return str.split("\n").map((line) => tabs + line).join("\n");
334
+ }
335
+ function replaceCodeBlocks(text) {
336
+ const codeBlockRegex = /```[\s\S]*?```/g;
337
+ return text.replace(codeBlockRegex, (match) => {
338
+ const code = match.slice(3, -3).trim();
339
+ return `${CODE_START}
340
+ ${indentString(code, 2)}
341
+ ${CODE_END}`;
342
+ });
343
+ }
321
344
  function createBasePrompt(apiFilePath, documentationPath) {
322
345
  const apiText = fs.readFileSync(apiFilePath, "utf8");
323
346
  const documentationText = documentationPath ? fs.readFileSync(documentationPath, "utf8") : "";
324
- const createTaskPrompt = fs.readFileSync(path.join(__dirname, "../prompts/create-task-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText);
347
+ const createTaskPrompt = fs.readFileSync(path.join(__dirname, "../prompts/create-task-prompt.md"), "utf8").replace("{{DOCUMENTATION}}", replaceCodeBlocks(documentationText)).replace("{{API}}", apiText);
325
348
  return createTaskPrompt;
326
349
  }
327
- const generateCode = async function(queryText, userChatHistory, createTaskPrompt, apiPath, debug = false, model = "gpt-4o") {
350
+ const generateCode = async function(queryText, userChatHistory, createTaskPrompt, debug = false, model = "gpt-4o-mini") {
328
351
  if (!queryText)
329
352
  return { code: "", loggableCode: "" };
330
- let generatedCode = "";
331
353
  const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
332
354
  const messages = [
333
355
  {
@@ -337,8 +359,7 @@ const generateCode = async function(queryText, userChatHistory, createTaskPrompt
337
359
  ...userChatHistory,
338
360
  {
339
361
  role: "user",
340
- content: `${queryText}.
341
- Respond only with code enclosed in \`\`\`.`,
362
+ content: `${queryText}. Respond with json`,
342
363
  name: "user"
343
364
  }
344
365
  ];
@@ -348,7 +369,23 @@ Respond only with code enclosed in \`\`\`.`,
348
369
  model,
349
370
  messages,
350
371
  temperature: 0,
351
- max_tokens: 700
372
+ max_tokens: 2e3,
373
+ response_format: {
374
+ json_schema: {
375
+ name: "codeResponse",
376
+ description: "The code generated by the AI",
377
+ schema: {
378
+ type: "object",
379
+ properties: {
380
+ yourCode: {
381
+ type: "string",
382
+ description: "The code generated by the AI"
383
+ }
384
+ }
385
+ }
386
+ },
387
+ type: "json_schema"
388
+ }
352
389
  }
353
390
  );
354
391
  if (debug)
@@ -356,21 +393,14 @@ Respond only with code enclosed in \`\`\`.`,
356
393
  const response = results.choices[0].message.content;
357
394
  if (debug)
358
395
  console.log(response);
359
- const codeStart = response.indexOf("```");
360
- const codeEnd = response.lastIndexOf("```");
361
- if (codeStart === -1 || codeEnd === -1 || codeStart === codeEnd) {
362
- return { code: "", loggableCode: "", rawResponse: response };
396
+ try {
397
+ const json = JSON.parse(response);
398
+ const code = json.yourCode.replaceAll("```", "");
399
+ return { code, loggableCode: code };
400
+ } catch (err) {
401
+ console.error("Error parsing response", err);
402
+ return { code: "", loggableCode: "" };
363
403
  }
364
- generatedCode = response.substring(codeStart + 3, codeEnd).replace("typescript", "");
365
- const codeHeader = `import * as ApiDefs from '${apiPath}'
366
- (async() {
367
- try {`;
368
- const codeFooter = `
369
- } catch(err) {
370
- console.error(err);
371
- }
372
- })();`;
373
- return { code: codeHeader + generatedCode + codeFooter, loggableCode: generatedCode };
374
404
  } catch (err) {
375
405
  console.error(err);
376
406
  return { code: "", loggableCode: "" };
@@ -383,7 +413,7 @@ async function createWithAPI(options) {
383
413
  apiGlobals: {},
384
414
  apiWhitelist: Object.getOwnPropertyNames(Object.getPrototypeOf(options.apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_")),
385
415
  debug: false,
386
- model: "gpt-4o",
416
+ model: "gpt-4o-mini",
387
417
  ...options
388
418
  };
389
419
  if (!options.apiObject || !options.apiDefFilePath) {
@@ -396,7 +426,7 @@ async function createWithAPI(options) {
396
426
  generateCode: async function(queryText, userChatHistory, currentContext = void 0) {
397
427
  if (!queryText)
398
428
  return { code: "", loggableCode: "" };
399
- return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug, model);
429
+ return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), debug, model);
400
430
  },
401
431
  runCode: async function(generatedCode) {
402
432
  if (!QuickJS) {
@@ -423,7 +453,7 @@ async function createWithAPI(options) {
423
453
  if (debug) {
424
454
  console.log("Running Code:\n", generatedCode);
425
455
  }
426
- const res = await runTask(generatedCode);
456
+ const res = await runTask(generatedCode.replace("'api.ts'", `'${options.apiDefFilePath}'`));
427
457
  if (!res) {
428
458
  console.error("Task unsuccessful");
429
459
  }
@@ -447,10 +477,10 @@ async function createWithAPI(options) {
447
477
  console.log("Query:", userQuery);
448
478
  }
449
479
  console.time("Generate Task");
450
- const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath);
480
+ const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""));
451
481
  console.timeEnd("Generate Task");
452
482
  console.time("Run Code");
453
- await this.runCode(generatedCode.code);
483
+ await this.runCode(generatedCode.code.replace("'api.ts'", `'${options.apiDefFilePath}'`));
454
484
  console.timeEnd("Run Code");
455
485
  return generatedCode;
456
486
  }
@@ -10,7 +10,7 @@ user: How are you today?
10
10
 
11
11
  assistant:
12
12
  ```
13
- orderingApi.respondToUser("I'm great, thanks for asking!");
13
+ orderingApi.respondToUser("I'm great, thanks for asking!");
14
14
  ```
15
15
 
16
16
  user: Add a hamburger with no cheese to my order
@@ -24,7 +24,7 @@ if (!item) {
24
24
  }
25
25
 
26
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?");
27
+ orderingApi.respondToUser("Ok, I added a Hamburger. What else would you like?");
28
28
  ```
29
29
 
30
30
  log: Added Hamburger with id 1
@@ -34,7 +34,7 @@ user: I'd like a large pizza with mushrooms
34
34
  assistant:
35
35
  ```
36
36
  orderingApi.addItemToOrder("Pizza", ["Large"], ["mushrooms"]);
37
- orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
37
+ orderingApi.respondToUser("Ok, I added a Large Pizza with mushrooms");
38
38
  ```
39
39
 
40
40
  user: Add a hamburger with bacon
@@ -48,7 +48,7 @@ if (!item) {
48
48
  }
49
49
 
50
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?");
51
+ orderingApi.respondToUser("Ok, I added a Hamburger with no cheese or onions. What else would you like?");
52
52
  ```
53
53
 
54
54
  log: Added Hamburger with id 2
@@ -64,7 +64,7 @@ if(existingItem) {
64
64
  orderingApi.respondToUser("Ok, I added jalapenos to your Hamburger");
65
65
  } else {
66
66
  orderingApi.respondToUser("Hmm, I can't find that item.");
67
- }
67
+ }
68
68
  ```
69
69
 
70
70
  user: Add a hamburger with no lettuce
@@ -78,7 +78,7 @@ if (!item) {
78
78
  }
79
79
 
80
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?");
81
+ orderingApi.respondToUser("Ok, I added a Hamburger with no cheese or onions. What else would you like?");
82
82
  ```
83
83
 
84
84
  log: Added Hamburger with id 2
@@ -88,5 +88,5 @@ user: I want an elephant.
88
88
 
89
89
  assistant:
90
90
  ```
91
- orderingApi.respondToUser("I'm sorry, but that isn't on our menu.");
91
+ orderingApi.respondToUser("I'm sorry, but that isn't on our menu.");
92
92
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aimyapi",
3
- "version": "0.1.15",
3
+ "version": "0.2.1",
4
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",
@@ -11,11 +11,22 @@ Here is the API that you will use:
11
11
 
12
12
  Documentation:
13
13
 
14
- Note: the api definitions are available as `ApiDefs`.
14
+ Write your code in this format:
15
+ ```
16
+ import * as ApiDefs from 'api.ts'
17
+
18
+ (async() {
19
+ try {
20
+ // ... your code here
21
+ } catch(err) {
22
+ console.error(err);
23
+ }
24
+ })();
25
+ ```
15
26
 
16
27
  {{DOCUMENTATION}}
17
28
 
18
- Current Context:
29
+ Contextual data:
19
30
  ```
20
31
  {{CONTEXT}}
21
32
  ```
package/src/index.ts CHANGED
@@ -13,19 +13,37 @@ const openai = new OpenAI({
13
13
  apiKey: process.env.OPENAI_API_KEY // This is also the default, can be omitted
14
14
  });
15
15
 
16
+ const CODE_START = `\`\`\`
17
+ import * as ApiDefs from 'api.ts'
16
18
 
17
- // function formatObject(obj: any): string {
18
- // return Object.keys(obj).reduce((acc, key) => {
19
- // return `${acc}${key}:\n${obj[key]}\n\n`;
20
- // }, "");
21
- // }
19
+ (async() {
20
+ try {`;
21
+
22
+ const CODE_END = ` } catch(err) {
23
+ console.error(err);
24
+ }
25
+ })();
26
+ \`\`\``;
27
+
28
+ function indentString(str, numTabs) {
29
+ const tabs = '\t'.repeat(numTabs);
30
+ return str.split('\n').map(line => tabs + line).join('\n');
31
+ }
32
+
33
+ function replaceCodeBlocks(text) {
34
+ const codeBlockRegex = /```[\s\S]*?```/g;
35
+ return text.replace(codeBlockRegex, (match) => {
36
+ const code = match.slice(3, -3).trim();
37
+ return `${CODE_START}\n${indentString(code, 2)}\n${CODE_END}`;
38
+ });
39
+ }
22
40
 
23
41
  export function createBasePrompt(apiFilePath:string, documentationPath: string): string {
24
42
  const apiText: string = fs.readFileSync(apiFilePath, 'utf8');
25
43
  const documentationText: string = documentationPath ? fs.readFileSync(documentationPath, 'utf8') : '';
26
44
 
27
45
  //console.time("Loading templates");
28
- const createTaskPrompt: string = fs.readFileSync( path.join(__dirname, '../prompts/create-task-prompt.md'), 'utf8').replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText);
46
+ const createTaskPrompt: string = fs.readFileSync( path.join(__dirname, '../prompts/create-task-prompt.md'), 'utf8').replace("{{DOCUMENTATION}}", replaceCodeBlocks(documentationText)).replace("{{API}}", apiText);
29
47
  //console.timeEnd("Loading templates")
30
48
 
31
49
  return createTaskPrompt;
@@ -38,11 +56,10 @@ export interface GenerateCodeResult {
38
56
  }
39
57
 
40
58
  // FIXME: add an options parameter and allow specifying the token limit
41
- export const generateCode = async function(queryText:string, userChatHistory:ChatCompletionMessageParam[], createTaskPrompt:string, apiPath:string, debug:boolean = false, model="gpt-4o"): Promise<GenerateCodeResult> {
59
+ export const generateCode = async function(queryText:string, userChatHistory:ChatCompletionMessageParam[], createTaskPrompt:string, debug:boolean = false, model="gpt-4o-mini"): Promise<GenerateCodeResult> {
42
60
  if(!queryText)
43
61
  return { code: '', loggableCode: '' };
44
62
 
45
- let generatedCode = '';
46
63
  const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
47
64
  const messages:ChatCompletionMessageParam[] = [
48
65
  {
@@ -52,16 +69,33 @@ export const generateCode = async function(queryText:string, userChatHistory:Cha
52
69
  ...userChatHistory,
53
70
  {
54
71
  role: "user",
55
- content: `${queryText}.\nRespond only with code enclosed in \`\`\`.`,
72
+ content: `${queryText}. Respond with json`,
56
73
  name: "user"
57
74
  }
58
75
  ];
76
+
59
77
  try {
60
78
  const results = await openai.chat.completions.create({
61
79
  model,
62
80
  messages: messages,
63
81
  temperature: 0.0,
64
- max_tokens: 700,
82
+ max_tokens: 2000,
83
+ response_format: {
84
+ json_schema: {
85
+ name: "codeResponse",
86
+ description: "The code generated by the AI",
87
+ schema: {
88
+ type: 'object',
89
+ properties: {
90
+ yourCode: {
91
+ type: 'string',
92
+ description: 'The code generated by the AI',
93
+ }
94
+ },
95
+ },
96
+ },
97
+ type: 'json_schema',
98
+ }
65
99
  }
66
100
  );
67
101
 
@@ -72,21 +106,16 @@ export const generateCode = async function(queryText:string, userChatHistory:Cha
72
106
 
73
107
  if(debug)
74
108
  console.log(response);
75
-
76
- // Return only the code between ``` and ``` (usually at the end of the completion)
77
- const codeStart = response.indexOf('```');
78
- const codeEnd = response.lastIndexOf('```');
79
-
80
- // error, no code detected inside the response
81
- if(codeStart === -1 || codeEnd === -1 || codeStart === codeEnd) {
82
- return { code: '', loggableCode: '', rawResponse: response };
109
+
110
+ try {
111
+ const json = JSON.parse(response);
112
+ const code = json.yourCode.replaceAll('```', '');
113
+
114
+ return { code, loggableCode: code };
115
+ } catch(err) {
116
+ console.error("Error parsing response", err);
117
+ return { code: '', loggableCode: '' };
83
118
  }
84
-
85
- generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
86
-
87
- const codeHeader = `import * as ApiDefs from '${apiPath}'\n(async() {\n\ttry {`;
88
- const codeFooter = `\n\t} catch(err) {\n\t\tconsole.error(err);\n\t}\n})();`;
89
- return { code: codeHeader + generatedCode + codeFooter, loggableCode: generatedCode };
90
119
  } catch(err) {
91
120
  console.error(err);
92
121
  return { code: '', loggableCode: '' };
@@ -124,7 +153,7 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<AIMyAPIInstance> {
124
153
  apiGlobals: {},
125
154
  apiWhitelist: Object.getOwnPropertyNames(Object.getPrototypeOf(options.apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_")),
126
155
  debug: false,
127
- model: "gpt-4o",
156
+ model: "gpt-4o-mini",
128
157
  ...options
129
158
  } as AIMyAPIOptions;
130
159
 
@@ -142,7 +171,7 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<AIMyAPIInstance> {
142
171
  if(!queryText)
143
172
  return { code: '', loggableCode: '' };
144
173
 
145
- return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug, model);
174
+ return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), debug, model);
146
175
  },
147
176
  runCode: async function(generatedCode:string) {
148
177
  if(!QuickJS) {
@@ -177,7 +206,7 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<AIMyAPIInstance> {
177
206
  console.log("Running Code:\n", generatedCode);
178
207
  }
179
208
 
180
- const res = await runTask(generatedCode);
209
+ const res = await runTask(generatedCode.replace("'api.ts'", `'${options.apiDefFilePath}'`));
181
210
 
182
211
  if(!res) {
183
212
  console.error("Task unsuccessful");
@@ -211,11 +240,11 @@ async function createWithAPI(options:AIMyAPIOptions): Promise<AIMyAPIInstance> {
211
240
 
212
241
  // Generate Code
213
242
  console.time("Generate Task")
214
- const generatedCode:GenerateCodeResult = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : "" ), apiDefFilePath);
243
+ const generatedCode:GenerateCodeResult = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : "" ));
215
244
  console.timeEnd("Generate Task")
216
245
 
217
246
  console.time("Run Code")
218
- await this.runCode(generatedCode.code);
247
+ await this.runCode(generatedCode.code.replace("'api.ts'", `'${options.apiDefFilePath}'`));
219
248
  console.timeEnd("Run Code")
220
249
 
221
250
  return generatedCode;
@@ -228,7 +257,7 @@ export interface AIMyAPIModuleExports {
228
257
  createWithAPI: (options:AIMyAPIOptions) => Promise<AIMyAPIInstance>;
229
258
 
230
259
  createBasePrompt: (apiFilePath:string, documentationPath: string) => string;
231
- generateCode: (queryText:string, userChatHistory:ChatCompletionMessageParam[], createTaskPrompt:string, apiPath:string, debug:boolean) => Promise<GenerateCodeResult>;
260
+ generateCode: (queryText:string, userChatHistory:ChatCompletionMessageParam[], createTaskPrompt:string, debug:boolean) => Promise<GenerateCodeResult>;
232
261
  createSandbox: (QuickJS:QuickJSWASMModule, globals: any) => Promise<any>;
233
262
  }
234
263