Skip to content

feat: Custom JSX runtime #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Dec 20, 2024
13 changes: 0 additions & 13 deletions .github/workflows/conventional-label.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"source.fixAll.eslint": "always",
"source.removeUnusedImports": "always"
},
"cSpell.words": ["gensx"]
"cSpell.words": ["gensx", "jsxs"]
}
16 changes: 11 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"packageManager": "[email protected]",
"type": "module",
"scripts": {
"build:watch": "pnpm build:clean && pnpm generate-dist --watch",
"dev": "nodemon",
"prepublishOnly": "pnpm i && pnpm build",
"build": "pnpm validate-typescript && pnpm build:clean && pnpm generate-dist",
Expand All @@ -38,22 +39,19 @@
"lint:fix": "eslint --ignore-path .gitignore . --ext .js,.ts --fix",
"lint:file": "eslint --ignore-path .gitignore",
"validate-typescript": "tsc -p tsconfig.prod.json --noEmit",
"generate-dist": "tsup src/index.ts --minify --tsconfig tsconfig.prod.json --dts --format cjs,esm --out-dir dist",
"generate-dist": "tsup src/index.ts --minify --tsconfig tsconfig.prod.json --dts --format cjs,esm --out-dir dist --entry.jsx-runtime=src/jsx-runtime.ts --entry.jsx-dev-runtime=src/jsx-dev-runtime.ts --entry.index=src/index.ts",
"build:clean": "rimraf dist; exit 0",
"prepare": "[ -f .husky/install.mjs ] && node .husky/install.mjs || true"
},
"dependencies": {
"openai": "^4.76.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"openai": "^4.76.0"
},
"devDependencies": {
"@swc/cli": "^0.5.2",
"@swc/core": "^1.10.1",
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.10.2",
"@types/react": "^19.0.1",
"@types/react-dom": "^18.3.2",
"@typescript-eslint/eslint-plugin": "^8.18.1",
"@typescript-eslint/parser": "^8.18.1",
"@vitest/coverage-istanbul": "^2.1.8",
Expand Down Expand Up @@ -94,6 +92,14 @@
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./jsx-runtime": {
"import": "./dist/jsx-runtime.js",
"require": "./dist/jsx-runtime.cjs"
},
"./jsx-dev-runtime": {
"import": "./dist/jsx-dev-runtime.js",
"require": "./dist/jsx-dev-runtime.cjs"
}
}
}
27 changes: 0 additions & 27 deletions playground/blog/BlogWritingWorkflow.tsx

This file was deleted.

178 changes: 106 additions & 72 deletions playground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,119 @@
import { Workflow } from "@/src/components/Workflow";
import { WorkflowContext } from "@/src/components/Workflow";
import { createWorkflowOutput } from "@/src/hooks/useWorkflowOutput";
import * as gsx from "@/index";

import { BlogWritingWorkflow } from "./blog/BlogWritingWorkflow";
import { TweetWritingWorkflow } from "./tweet/TweetWritingWorkflow";

async function runParallelWorkflow() {
const title = "Programmatic Secrets with ESC";
const prompt = "Write an article...";

const [blogPost, setBlogPost] = createWorkflowOutput("");
const [tweet, setTweet] = createWorkflowOutput("");

const workflow = (
<Workflow>
<BlogWritingWorkflow
title={title}
prompt={prompt}
setOutput={setBlogPost}
/>
<TweetWritingWorkflow content={blogPost} setOutput={setTweet} />
</Workflow>
);

const context = new WorkflowContext(workflow);
await context.execute();
interface LLMResearchBrainstormProps {
prompt: string;
}
type LLMResearchBrainstormOutput = string[];
const LLMResearchBrainstorm = gsx.Component<
LLMResearchBrainstormProps,
LLMResearchBrainstormOutput
>(async ({ prompt }) => {
console.log("🔍 Starting research for:", prompt);
const topics = await Promise.resolve(["topic 1", "topic 2", "topic 3"]);
return topics;
});

console.log("\n=== Parallel Workflow Results ===");
console.log("Blog Post:", await blogPost);
console.log("Tweet:", await tweet);
interface LLMResearchProps {
topic: string;
}
type LLMResearchOutput = string;
const LLMResearch = gsx.Component<LLMResearchProps, LLMResearchOutput>(
async ({ topic }) => {
console.log("📚 Researching topic:", topic);
return await Promise.resolve(`research results for ${topic}`);
},
);

async function runNestedWorkflow() {
const title = "Programmatic Secrets with ESC";
const prompt = "Write an article...";
interface LLMWriterProps {
research: string;
prompt: string;
}
type LLMWriterOutput = string;
const LLMWriter = gsx.Component<LLMWriterProps, LLMWriterOutput>(
async ({ research, prompt }) => {
console.log("✍️ Writing draft based on research");
return await Promise.resolve(
`**draft\n${research}\n${prompt}\n**end draft`,
);
},
);

let blogPost = "";
let tweet = "";
interface LLMEditorProps {
draft: string;
}
type LLMEditorOutput = string;
const LLMEditor = gsx.Component<LLMEditorProps, LLMEditorOutput>(
async ({ draft }) => {
console.log("✨ Polishing final draft");
return await Promise.resolve(`edited result: ${draft}`);
},
);

const workflow = (
<Workflow>
<BlogWritingWorkflow
title={
new Promise(resolve => {
resolve(title);
})
}
prompt={prompt}
>
{blogPostResult => (
<TweetWritingWorkflow content={blogPostResult}>
{tweetResult => {
blogPost = blogPostResult;
tweet = tweetResult;
return null;
}}
</TweetWritingWorkflow>
)}
</BlogWritingWorkflow>
</Workflow>
);
interface WebResearcherProps {
prompt: string;
}
type WebResearcherOutput = string[];
const WebResearcher = gsx.Component<WebResearcherProps, WebResearcherOutput>(
async ({ prompt }) => {
console.log("🌐 Researching web for:", prompt);
const results = await Promise.resolve([
"web result 1",
"web result 2",
"web result 3",
]);
return results;
},
);

const context = new WorkflowContext(workflow);
await context.execute();
type ParallelResearchOutput = [string[], string[]];
interface ParallelResearchComponentProps {
prompt: string;
}
const ParallelResearch = gsx.Component<
ParallelResearchComponentProps,
ParallelResearchOutput
>(({ prompt }) => (
<>
<LLMResearchBrainstorm prompt={prompt}>
{topics => topics.map(topic => <LLMResearch topic={topic} />)}
</LLMResearchBrainstorm>
<WebResearcher prompt={prompt} />
</>
));

console.log("\n=== Nested Workflow Results ===");
console.log("Blog Post:", blogPost);
console.log("Tweet:", tweet);
interface BlogWritingWorkflowProps {
prompt: string;
}
type BlogWritingWorkflowOutput = string;
const BlogWritingWorkflow = gsx.Component<
BlogWritingWorkflowProps,
BlogWritingWorkflowOutput
>(async ({ prompt }) => (
<ParallelResearch prompt={prompt}>
{([catalogResearch, webResearch]) => {
console.log("🧠 Research:", { catalogResearch, webResearch });
return (
<LLMWriter
research={[catalogResearch.join("\n"), webResearch.join("\n")].join(
"\n\n",
)}
prompt={prompt}
>
{draft => <LLMEditor draft={draft} />}
</LLMWriter>
);
}}
</ParallelResearch>
));

async function main() {
try {
await runParallelWorkflow();
await runNestedWorkflow();
} catch (error) {
console.error("Workflow execution failed:", error);
process.exit(1);
}
console.log("🚀 Starting blog writing workflow");

// Use the gensx function to execute the workflow and annotate with the output type.
const result = await gsx.execute<string>(
<BlogWritingWorkflow prompt="Write a blog post about the future of AI" />,
);
console.log("✅ Final result:", { result });
}

main().catch((error: unknown) => {
console.error("Unhandled error:", error);
process.exit(1);
});
await main();
12 changes: 0 additions & 12 deletions playground/shared/components/LLMEditor.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions playground/shared/components/LLMResearcher.tsx

This file was deleted.

32 changes: 0 additions & 32 deletions playground/shared/components/LLMWriter.tsx

This file was deleted.

21 changes: 0 additions & 21 deletions playground/tweet/TweetWritingWorkflow.tsx

This file was deleted.

Loading
Loading