branch:
server.ts
2080 bytesRaw
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";
import { AIChatAgent, createToolsFromClientSchemas } from "@cloudflare/ai-chat";
import {
  streamText,
  convertToModelMessages,
  pruneMessages,
  stepCountIs
} from "ai";

/**
 * Dynamic Tools Agent — demonstrates the SDK/platform pattern.
 *
 * This server does NOT define any tools at deploy time. Instead, it accepts
 * tool schemas from the client via `options.clientTools` and registers them
 * dynamically using `createToolsFromClientSchemas()`.
 *
 * This is the pattern you would use when building an SDK or platform where
 * third-party developers define tools in their embedding application,
 * and the server is shared infrastructure they do not control.
 */
export class DynamicToolsAgent extends AIChatAgent {
  async onChatMessage(
    _onFinish: Parameters<AIChatAgent["onChatMessage"]>[0],
    options: Parameters<AIChatAgent["onChatMessage"]>[1]
  ) {
    const workersai = createWorkersAI({ binding: this.env.AI });

    const result = streamText({
      model: workersai("@cf/moonshotai/kimi-k2.5", {
        sessionAffinity: this.sessionAffinity
      }),
      system:
        "You are a helpful assistant. You have access to tools provided by " +
        "the embedding application. Use them when asked. If no tools are " +
        "available, let the user know they can enable tools in the sidebar.",
      messages: pruneMessages({
        messages: await convertToModelMessages(this.messages),
        toolCalls: "before-last-2-messages",
        reasoning: "before-last-message"
      }),
      // Dynamic tools from client — the server does not know these at deploy time
      tools: createToolsFromClientSchemas(options?.clientTools),
      stopWhen: stepCountIs(5)
    });

    return result.toUIMessageStreamResponse();
  }
}

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