branch:
server.ts
5207 bytesRaw
import { routeAgentRequest, routeAgentEmail, getAgentByName } from "agents";
import {
  createAddressBasedEmailResolver,
  createSecureReplyEmailResolver
} from "agents/email";
import { PlaygroundMcpServer as McpServerClass } from "./demos/mcp/mcp-server-agent";

const mcpHandler = McpServerClass.serve("/mcp-server", {
  binding: "PlaygroundMcpServer"
});

// Core agents
export { StateAgent } from "./demos/core/state-agent";
export { CallableAgent } from "./demos/core/callable-agent";
export { StreamingAgent } from "./demos/core/streaming-agent";
export { ScheduleAgent } from "./demos/core/schedule-agent";
export { SqlAgent } from "./demos/core/sql-agent";
export { ConnectionsAgent } from "./demos/core/connections-agent";
export { RoutingAgent } from "./demos/core/routing-agent";
export { ReadonlyAgent } from "./demos/core/readonly-agent";
export { RetryAgent } from "./demos/core/retry-agent";

// AI agents
export { ChatAgent } from "./demos/ai/chat-agent";
export { ToolsAgent } from "./demos/ai/tools-agent";
export { CodemodeAgent } from "./demos/ai/codemode-agent";

// Multi-agent demos
export { SupervisorAgent } from "./demos/multi-agent/supervisor-agent";
export { ChildAgent } from "./demos/multi-agent/child-agent";
export { LobbyAgent } from "./demos/multi-agent/lobby-agent";
export { RoomAgent } from "./demos/multi-agent/room-agent";
export { ManagerAgent } from "./demos/multi-agent/manager-agent";
export { FanoutWorkerAgent } from "./demos/multi-agent/fanout-worker-agent";
export { PipelineOrchestratorAgent } from "./demos/multi-agent/pipeline-agent";
export {
  ValidatorStageAgent,
  TransformStageAgent,
  EnrichStageAgent
} from "./demos/multi-agent/stage-agents";

// MCP demos
export { PlaygroundMcpServer } from "./demos/mcp/mcp-server-agent";
export { McpClientAgent } from "./demos/mcp/mcp-client-agent";

// Workflow demos
export { BasicWorkflowAgent } from "./demos/workflow/basic-workflow-agent";
export { ApprovalAgent } from "./demos/workflow/approval-agent";
export { ProcessingWorkflow } from "./demos/workflow/processing-workflow";
export { ApprovalWorkflow } from "./demos/workflow/approval-workflow";

// Email agents
export { ReceiveEmailAgent } from "./demos/email/receive-email-agent";
export { SecureEmailAgent } from "./demos/email/secure-email-agent";

// Voice agents
export { PlaygroundVoiceAgent } from "./demos/voice/voice-agent";

export default {
  /**
   * Email handler for Cloudflare Email Routing
   *
   * Routes emails to the appropriate agent based on:
   * 1. Secure reply headers (for replies to signed outbound emails)
   * 2. Address-based routing (e.g., receive+instanceId@domain)
   */
  async email(message: ForwardableEmailMessage, env: Env) {
    console.log("📮 Email received:", message.from, "->", message.to);

    // Create resolvers
    const secureResolver = createSecureReplyEmailResolver(
      env.EMAIL_SECRET || "demo-secret-not-configured"
    );

    // Address-based routing:
    // - "receive+id@domain" routes to ReceiveEmailAgent with agentId "id"
    // - "secure+id@domain" routes to SecureEmailAgent with agentId "id"
    // - Plain addresses default to ReceiveEmailAgent
    const addressResolver =
      createAddressBasedEmailResolver("ReceiveEmailAgent");

    await routeAgentEmail(message, env, {
      resolver: async (email, env) => {
        // First check if this is a secure reply (has valid signed headers)
        const secureReply = await secureResolver(email, env);
        if (secureReply) {
          console.log(
            "🔐 Routing as secure reply to:",
            secureReply.agentName,
            secureReply.agentId
          );
          return secureReply;
        }

        // Otherwise route based on address
        const addressRoute = await addressResolver(email, env);
        if (addressRoute) {
          console.log(
            "📧 Routing by address to:",
            addressRoute.agentName,
            addressRoute.agentId
          );
        }
        return addressRoute;
      },
      onNoRoute: async (email) => {
        console.warn(
          "⚠️ No route found for email:",
          email.from,
          "->",
          email.to
        );
      }
    });
  },

  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const url = new URL(request.url);

    // MCP server endpoint — handles both SSE and Streamable HTTP
    if (url.pathname.startsWith("/mcp-server")) {
      return mcpHandler.fetch(request, env, ctx);
    }

    // Custom basePath routing example:
    // Routes /custom-routing/{instanceName} to a RoutingAgent instance.
    // The server controls which agent instance handles the request,
    // and the client connects using `basePath` instead of `agent` + `name`.
    if (url.pathname.startsWith("/custom-routing/")) {
      const instanceName = url.pathname.replace("/custom-routing/", "");
      if (instanceName) {
        const agent = await getAgentByName(env.RoutingAgent, instanceName);
        return agent.fetch(request);
      }
    }

    return (
      (await routeAgentRequest(request, env)) ||
      new Response("Not found", { status: 404 })
    );
  }
} satisfies ExportedHandler<Env>;