initial commit

This commit is contained in:
Marcus Schiesser
2024-09-13 16:15:57 +07:00
commit 52b02c7efb
5 changed files with 5068 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
node_modules
+123
View File
@@ -0,0 +1,123 @@
import {
Context,
StartEvent,
StopEvent,
Workflow,
WorkflowEvent,
} from "@llamaindex/core/workflow";
import { OpenAI } from "llamaindex";
const MAX_REVIEWS = 3;
// Using the o1-preview model (see https://platform.openai.com/docs/guides/reasoning?reasoning-prompt-examples=coding-planning)
const llm = new OpenAI({ model: "o1-preview", temperature: 1 });
// example specification from https://platform.openai.com/docs/guides/reasoning?reasoning-prompt-examples=coding-planning
const specification = `Python app that takes user questions and looks them up in a
database where they are mapped to answers. If there is a close match, it retrieves
the matched answer. If there isn't, it asks the user to provide an answer and
stores the question/answer pair in the database.`;
// Create custom event types
export class MessageEvent extends WorkflowEvent<{ msg: string }> {}
export class CodeEvent extends WorkflowEvent<{ code: string }> {}
export class ReviewEvent extends WorkflowEvent<{
review: string;
code: string;
}> {}
// Helper function to truncate long strings
const truncate = (str: string) => {
const MAX_LENGTH = 60;
if (str.length <= MAX_LENGTH) return str;
return str.slice(0, MAX_LENGTH) + "...";
};
// the architect is responsible for writing the structure and the initial code based on the specification
const architect = async (context: Context, ev: StartEvent) => {
// get the specification from the start event and save it to context
context.set("specification", ev.data.input);
const spec = context.get("specification");
// write a message to send an update to the user
context.writeEventToStream(
new MessageEvent({
msg: `Writing app using this specification: ${truncate(spec)}`,
}),
);
const prompt = `Build an app for this specification: <spec>${spec}</spec>. Make a plan for the directory structure you'll need, then return each file in full. Don't supply any reasoning, just code.`;
const code = await llm.complete({ prompt });
return new CodeEvent({ code: code.text });
};
// the coder is responsible for updating the code based on the review
const coder = async (context: Context, ev: ReviewEvent) => {
// get the specification from the context
const spec = context.get("specification");
// get the latest review and code
const { review, code } = ev.data;
// write a message to send an update to the user
context.writeEventToStream(
new MessageEvent({
msg: `Update code based on review: ${truncate(review)}`,
}),
);
const prompt = `We need to improve code that should implement this specification: <spec>${spec}</spec>. Here is the current code: <code>${code}</code>. And here is a review of the code: <review>${review}</review>. Improve the code based on the review, keep the specification in mind, and return the full updated code. Don't supply any reasoning, just code.`;
const updatedCode = await llm.complete({ prompt });
return new CodeEvent({ code: updatedCode.text });
};
// the reviewer is responsible for reviewing the code and providing feedback
const reviewer = async (context: Context, ev: CodeEvent) => {
// get the specification from the context
const spec = context.get("specification");
// get latest code from the event
const { code } = ev.data;
// update and check the number of reviews
const numberReviews = context.get("numberReviews", 0) + 1;
context.set("numberReviews", numberReviews);
if (numberReviews > MAX_REVIEWS) {
// the we've done this too many times - return the code
context.writeEventToStream(
new MessageEvent({
msg: `Already reviewed ${numberReviews - 1} times, stopping!`,
}),
);
return new StopEvent({ result: code });
}
// write a message to send an update to the user
context.writeEventToStream(
new MessageEvent({ msg: `Review #${numberReviews}: ${truncate(code)}` }),
);
const prompt = `Review this code: <code>${code}</code>. Check if the code quality and whether it correctly implements this specification: <spec>${spec}</spec>. If you're satisfied, just return 'Looks great', nothing else. If not, return a review with a list of changes you'd like to see.`;
const review = (await llm.complete({ prompt })).text;
if (review.includes("Looks great")) {
// the reviewer is satisfied with the code, let's return the review
context.writeEventToStream(
new MessageEvent({
msg: `Reviewer says: ${review}`,
}),
);
return new StopEvent({ result: code });
}
return new ReviewEvent({ review, code });
};
const codeAgent = new Workflow({ validate: true });
codeAgent.addStep(StartEvent, architect, { outputs: CodeEvent });
codeAgent.addStep(ReviewEvent, coder, { outputs: CodeEvent });
codeAgent.addStep(CodeEvent, reviewer, { outputs: ReviewEvent });
// Usage
async function main() {
const run = codeAgent.run(specification);
for await (const event of codeAgent.streamEvents()) {
const msg = (event as MessageEvent).data.msg;
console.log(`${msg}\n`);
}
const result = await run;
console.log("Final code:\n", result.data.result);
}
main().catch(console.error);
+21
View File
@@ -0,0 +1,21 @@
{
"name": "app-creator",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "tsx main.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@llamaindex/core": "^0.2.0",
"llamaindex": "^0.6.0"
},
"devDependencies": {
"prettier": "^3.3.3",
"tsx": "^4.19.1"
}
}
+4909
View File
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"lib": [
"es2022"
],
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}