144 lines · 3.8 KB · TypeScript
RawDownload
// docs:start basicimport { agentOS, setup } from "@rivet-dev/agentos";import pi from "@agentos-software/pi";import { actor } from "rivetkit";import { type WorkflowStepContextOf, workflow } from "rivetkit/workflow"; const vm = agentOS({ software: [pi] }); interface BugFixInput {	repo: string;	issue: string;} // Each actor instance is one durable workflow run. Its creation input is stored// in actor state, so no queue is needed to trigger or order agent prompts.const bugFixer = actor({	state: {		repo: "",		issue: "",		status: "running" as "running" | "complete",		exitCode: null as number | null,	},	onCreate: (c, input: BugFixInput) => {		c.state.repo = input.repo;		c.state.issue = input.issue;	},	run: workflow(async (ctx) => {		await ctx.step("clone-repo", (step) => cloneRepo(step, step.state.repo));		await ctx.step("fix-bug", (step) =>			fixBugWithAgent(step, step.state.issue),		);		const exitCode = await ctx.step("run-tests", (step) => runTests(step));		await ctx.step("record-result", async (step) => {			step.state.exitCode = exitCode;			step.state.status = "complete";		});	}),	actions: {		getState: (c) => c.state,	},}); async function cloneRepo(	step: WorkflowStepContextOf<typeof bugFixer>,	repo: string,): Promise<void> {	const agent = step.client<typeof registry>().vm.getOrCreate("bug-fixer");	await agent.exec(`git clone ${repo} /home/agentos/repo`);} async function fixBugWithAgent(	step: WorkflowStepContextOf<typeof bugFixer>,	issue: string,): Promise<void> {	const agent = step.client<typeof registry>().vm.getOrCreate("bug-fixer");	await agent.openSession({		agent: "pi",		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },	});	await agent.prompt({		content: [{ type: "text", text: `Fix the bug described in issue: ${issue}` }],	});} async function runTests(	step: WorkflowStepContextOf<typeof bugFixer>,): Promise<number> {	const agent = step.client<typeof registry>().vm.getOrCreate("bug-fixer");	const tests = await agent.exec("cd /home/agentos/repo && npm test");	return tests.exitCode;}// docs:end basic // docs:start chaininginterface CodeReviewInput {	filePath: string;} const codeReviewer = actor({	state: {		filePath: "",		status: "running" as "running" | "complete",	},	onCreate: (c, input: CodeReviewInput) => {		c.state.filePath = input.filePath;	},	run: workflow(async (ctx) => {		await ctx.step("review", (step) =>			reviewCode(step, step.state.filePath),		);		const review = await ctx.step("read-review", (step) => readReview(step));		await ctx.step("fix", (step) => applyReview(step, review));		await ctx.step("record-review", async (step) => {			step.state.status = "complete";		});	}),	actions: {		getState: (c) => c.state,	},}); async function reviewCode(	step: WorkflowStepContextOf<typeof codeReviewer>,	filePath: string,): Promise<void> {	const agent = step.client<typeof registry>().vm.getOrCreate("reviewer");	await agent.openSession({		agent: "pi",		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },	});	await agent.prompt({		content: [			{				type: "text",				text: `Review ${filePath} and write findings to /home/agentos/review.md`,			},		],	});} async function readReview(	step: WorkflowStepContextOf<typeof codeReviewer>,): Promise<string> {	const agent = step.client<typeof registry>().vm.getOrCreate("reviewer");	return new TextDecoder().decode(		await agent.readFile("/home/agentos/review.md"),	);} async function applyReview(	step: WorkflowStepContextOf<typeof codeReviewer>,	review: string,): Promise<void> {	const agent = step.client<typeof registry>().vm.getOrCreate("reviewer");	await agent.prompt({		content: [			{ type: "text", text: `Apply the following review feedback:\n\n${review}` },		],	});} export const registry = setup({ use: { vm, bugFixer, codeReviewer } });registry.start();// docs:end chaining