branch:
server.ts
4030 bytesRaw
import { Agent, type AgentInputItem, run, withTrace } from "@openai/agents";
import { Agent as CFAgent, callable, routeAgentRequest } from "agents";
import { z } from "zod";

const EvaluationFeedback = z.object({
  feedback: z.string(),
  score: z.enum(["pass", "needs_improvement", "fail"])
});

export type Attempt = {
  description: string;
  slogan: string;
  feedback?: string;
  score: "pass" | "needs_improvement" | "fail";
};

export type CFAgentState = {
  chosenSlogan?: string;
  status?: string;
  attempts: Attempt[];
};

export class MyAgent extends CFAgent<Env, CFAgentState> {
  initialState: CFAgentState = {
    attempts: []
  };

  shouldReset = false;

  marketingAgent = new Agent({
    name: "Marketer",
    instructions:
      "You are a marketing wizard and you come up with good slogans based on user requests. If there is any feedback, use it to improve the slogan. Return only the slogan."
  });

  evaluator = new Agent({
    name: "Evaluator",
    instructions:
      "You evaluate marketing slogans. You will provide a score and possible feedback on how it can be improved. Do not directly suggest new slogans, your job is to judge. Never accept the very first attempt.",
    outputType: EvaluationFeedback
  });

  setStatus(status: string) {
    console.log("[MyAgent] Updating status", status);
    this.setState({
      ...this.state,
      status
    });
  }

  @callable()
  async generateSlogan(description: string) {
    console.log(
      `[MyAgent] generateSlogan method called with description: "${description}"`
    );

    await withTrace("LLM as a judge", async () => {
      let inputItems: AgentInputItem[] = [
        { role: "user", content: description }
      ];
      this.shouldReset = false;
      while (this.state.attempts.length <= 15 && !this.shouldReset) {
        console.log("[MyAgent] Starting agent run...");
        this.setStatus("🤔 Generating");
        const sloganResult = await run(this.marketingAgent, inputItems);
        const slogan = sloganResult.finalOutput;
        if (slogan === undefined) {
          console.warn("Failed to return slogan");
          return;
        }
        console.log("[MyAgent] Evaluating slogan:", slogan);
        this.setStatus("🧑‍⚖️ Judging");
        // Ensure the whole history is present
        inputItems = sloganResult.history;
        const evaluationResult = await run(this.evaluator, inputItems);
        const attempts = this.state.attempts;
        const evaluation = evaluationResult.finalOutput as
          | { feedback: string; score: "pass" | "needs_improvement" | "fail" }
          | undefined;
        attempts.push({
          description,
          slogan,
          feedback: evaluation?.feedback || "",
          score: evaluation?.score || "fail"
        });
        // Updating state syncs to all connected clients
        this.setState({
          ...this.state,
          attempts
        });
        if (evaluation?.score === "pass") {
          console.log("[MyAgent] Slogan passed judgment", slogan);
          this.setState({
            ...this.state,
            status: "🏆 We have a winner",
            chosenSlogan: slogan
          });
          return;
        }
        if (evaluation?.feedback) {
          inputItems.push({
            role: "user",
            content: `Feedback: ${evaluation.feedback}`
          });
        }
      }
    });
  }
  @callable()
  async reset() {
    this.setState({ attempts: [] });
    this.shouldReset = true;
  }
}

export default {
  async fetch(request: Request, env: Env, _ctx: ExecutionContext) {
    console.log(`[Server] Handling request: ${request.method} ${request.url}`);

    const response = await routeAgentRequest(request, env);

    if (response) {
      console.log(
        `[Server] Agent request routed successfully, status: ${response.status}`
      );
      return response;
    }
    console.log("[Server] No agent route matched, returning 404");
    return new Response("Not found", { status: 404 });
  }
};