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 +55 -25
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +55 -25
- package/dist/index.mjs +55 -25
- package/example/ordering_api.md +7 -7
- package/package.json +1 -1
- package/prompts/create-task-prompt.md +13 -2
- package/src/index.ts +59 -30
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,
|
|
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:
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
return { code
|
|
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) + "```" : ""),
|
|
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) + "```" : "")
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
return { code
|
|
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) + "```" : ""),
|
|
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) + "```" : "")
|
|
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,
|
|
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:
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
return { code
|
|
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) + "```" : ""),
|
|
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) + "```" : "")
|
|
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
|
}
|
package/example/ordering_api.md
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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,
|
|
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}
|
|
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:
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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) + "```" : ""),
|
|
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) + "```" : "" )
|
|
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,
|
|
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
|
|