├── .husky └── pre-commit ├── examples ├── mcp-client │ ├── public │ │ └── normalize.css │ ├── tsconfig.json │ ├── .dev.vars.example │ ├── index.html │ ├── package.json │ ├── vite.config.ts │ ├── wrangler.jsonc │ ├── README.md │ └── src │ │ └── styles.css ├── codemode │ ├── src │ │ └── tools.ts │ ├── .env.example │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── vite.config.ts │ ├── index.html │ ├── package.json │ ├── README.md │ ├── env.d.ts │ └── wrangler.jsonc ├── tictactoe │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── vite.config.ts │ ├── index.html │ ├── README.md │ ├── package.json │ └── wrangler.jsonc ├── a2a │ ├── tsconfig.json │ ├── src │ │ └── express-alias.js │ ├── README.md │ ├── package.json │ ├── vite.config.ts │ └── wrangler.jsonc ├── mcp │ ├── tsconfig.json │ ├── src │ │ ├── client.tsx │ │ ├── svg.d.ts │ │ └── mcp-icon.svg │ ├── index.html │ ├── vite.config.ts │ ├── env.d.ts │ ├── package.json │ ├── wrangler.jsonc │ └── README.md ├── playground │ ├── .dev.vars.example │ ├── src │ │ ├── model.ts │ │ ├── agents │ │ │ ├── stateful.ts │ │ │ ├── rpc.ts │ │ │ └── chat.ts │ │ ├── server.ts │ │ ├── shared.ts │ │ ├── styles.css │ │ └── components │ │ │ └── Chat.css │ ├── public │ │ └── favicon.ico │ ├── tsconfig.json │ ├── index.html │ ├── package.json │ ├── vite.config.ts │ ├── README.md │ ├── wrangler.jsonc │ └── env.d.ts ├── x402 │ ├── tsconfig.json │ ├── package.json │ ├── wrangler.jsonc │ └── worker-configuration.d.ts ├── x402-mcp │ ├── tsconfig.json │ ├── package.json │ ├── wrangler.jsonc │ └── worker-configuration.d.ts ├── cross-domain │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── env.d.ts │ ├── vite.config.ts │ ├── index.html │ ├── README.md │ ├── wrangler.jsonc │ ├── package.json │ └── src │ │ └── styles.css ├── mcp-worker │ ├── tsconfig.json │ ├── wrangler.jsonc │ ├── package.json │ ├── README.md │ └── src │ │ └── index.ts ├── resumable-stream-chat │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── src │ │ ├── index.tsx │ │ └── server.ts │ ├── vite.config.ts │ ├── package.json │ ├── wrangler.jsonc │ └── index.html ├── mcp-elicitation │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── README.md │ ├── package.json │ └── wrangler.jsonc ├── mcp-worker-authenticated │ ├── tsconfig.json │ ├── wrangler.jsonc │ ├── package.json │ ├── README.md │ └── src │ │ └── index.ts └── email-agent │ ├── tsconfig.json │ ├── package.json │ ├── wrangler.jsonc │ └── test-mail.ts ├── .prettierrc ├── .prettierignore ├── openai-sdk ├── basic │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── favicon.ico │ ├── src │ │ ├── client.tsx │ │ └── server.ts │ ├── vite.config.ts │ ├── index.html │ ├── package.json │ ├── wrangler.jsonc │ └── env.d.ts ├── handoffs │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── favicon.ico │ ├── src │ │ ├── client.tsx │ │ └── server.ts │ ├── vite.config.ts │ ├── package.json │ ├── index.html │ └── wrangler.jsonc ├── human-in-the-loop │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── favicon.ico │ ├── vite.config.ts │ ├── package.json │ ├── index.html │ └── wrangler.jsonc ├── llm-as-a-judge │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── favicon.ico │ ├── vite.config.ts │ ├── package.json │ ├── index.html │ └── wrangler.jsonc ├── chess-app │ ├── tsconfig.json │ ├── index.html │ ├── vite.config.ts │ ├── worker-configuration.d.ts │ ├── wrangler.jsonc │ ├── package.json │ ├── README.md │ └── src │ │ └── index.ts ├── call-my-agent │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── README.md │ ├── vite.config.ts │ ├── index.html │ ├── wrangler.jsonc │ └── package.json └── pizzaz │ ├── package.json │ ├── wrangler.jsonc │ └── README.md ├── site ├── agents │ ├── src │ │ ├── .env_example │ │ ├── env.d.ts │ │ ├── fonts │ │ │ ├── InterVariable.woff2 │ │ │ └── InterVariable-Italic.woff2 │ │ ├── components │ │ │ ├── gsap.ts │ │ │ ├── links.ts │ │ │ ├── _components │ │ │ │ ├── install-command.tsx │ │ │ │ ├── chat-bubble.tsx │ │ │ │ └── background.tsx │ │ │ ├── logo.tsx │ │ │ └── use-interval.ts │ │ ├── styles │ │ │ └── globals.css │ │ ├── layouts │ │ │ └── Layout.astro │ │ └── server │ │ │ └── index.ts │ ├── public │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── InterVariable.woff2 │ │ │ └── InterVariable-Italic.woff2 │ │ ├── file.svg │ │ ├── window.svg │ │ └── globe.svg │ ├── postcss.config.mjs │ ├── tailwind.config.js │ ├── env.d.ts │ ├── wrangler.jsonc │ ├── astro.config.ts │ ├── tsconfig.json │ └── package.json └── ai-playground │ ├── tsconfig.json │ ├── public │ └── favicon.ico │ ├── src │ ├── client.tsx │ ├── models.ts │ ├── index.css │ ├── utils.ts │ └── components │ │ ├── ModelRow.tsx │ │ ├── ReasoningCard.tsx │ │ ├── Icons.tsx │ │ └── LocalhostWarningModal.tsx │ ├── vite.config.ts │ ├── package.json │ ├── index.html │ ├── wrangler.jsonc │ ├── tailwind.config.ts │ └── README.md ├── guides ├── human-in-the-loop │ ├── .dev.vars.example │ ├── tsconfig.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ └── client.tsx │ ├── index.html │ ├── package.json │ ├── wrangler.toml │ └── vite.config.ts └── anthropic-patterns │ ├── tsconfig.json │ ├── .dev.vars.example │ ├── public │ ├── favicon.ico │ └── flows │ │ ├── 02 routing.png │ │ ├── 03 parallel.png │ │ ├── 05 evaluator.png │ │ ├── 01 sequential.png │ │ └── 04 orchestrator.png │ ├── src │ ├── types.d.ts │ ├── client.tsx │ ├── layout.tsx │ └── flows │ │ ├── 02 routing.txt │ │ ├── 01 sequential.txt │ │ ├── 04 orchestrator.txt │ │ └── 03 parallel.txt │ ├── index.html │ ├── package.json │ ├── vite.config.ts │ └── wrangler.json ├── packages ├── hono-agents │ ├── tsconfig.json │ ├── scripts │ │ └── build.ts │ └── package.json └── agents │ ├── src │ ├── cli │ │ ├── index.ts │ │ └── create.ts │ ├── cli-tests │ │ └── vitest.config.ts │ ├── tests │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ ├── alarms.test.ts │ │ ├── wrangler.jsonc │ │ └── schedule.test.ts │ ├── mcp │ │ ├── client-storage.ts │ │ ├── auth-context.ts │ │ ├── types.ts │ │ ├── errors.ts │ │ └── client-transports.ts │ ├── react-tests │ │ └── vitest.config.ts │ ├── observability │ │ ├── mcp.ts │ │ ├── base.ts │ │ ├── agent.ts │ │ └── index.ts │ ├── tests-d │ │ ├── untyped-use-agent-stub.test-d.ts │ │ ├── untyped-use-agent.test-d.ts │ │ ├── example-stub.test-d.ts │ │ ├── example.test-d.ts │ │ ├── use-agent-stub.test-d.ts │ │ └── typed-use-agent.test-d.ts │ ├── context.ts │ ├── serializable.ts │ ├── core │ │ └── events.ts │ └── e2e │ │ └── remote-mcp-server │ │ └── mcp.ts │ ├── tsconfig.json │ ├── evals │ ├── vite.config.ts │ └── README.md │ └── scripts │ └── build.ts ├── .vscode ├── extensions.json └── settings.json ├── .mcp.json ├── .github ├── changeset-publish.ts ├── changeset-version.ts ├── ISSUE_TEMPLATE │ └── bug_report.md ├── version-script.ts ├── workflows │ ├── pkg-pr-new.yml │ ├── pullrequest.yml │ └── claude.yml └── resolve-workspace-versions.ts ├── .changeset ├── config.json └── README.md ├── docs ├── index.md ├── client-tools-continuation.md └── observability.md ├── patches └── @changesets+cli+2.29.7.patch ├── licenses ├── README.md ├── mit-anthropic-mcp-ts-sdk.txt └── mit-ethanniser-x402-mcp.txt ├── NOTICE ├── assets └── npm-install-agents.svg ├── LICENSE ├── scripts └── typecheck.ts ├── biome.json └── README.md /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /examples/mcp-client/public/normalize.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none" 3 | } 4 | -------------------------------------------------------------------------------- /examples/codemode/src/tools.ts: -------------------------------------------------------------------------------- 1 | export const tools = {}; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | packages/agents/CHANGELOG.md 2 | site/agents/.astro 3 | -------------------------------------------------------------------------------- /examples/codemode/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | -------------------------------------------------------------------------------- /examples/tictactoe/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /openai-sdk/basic/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /site/agents/src/.env_example: -------------------------------------------------------------------------------- 1 | GITHUB_TOKEN=optional-to-avoid-rate-limiting -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /examples/a2a/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/mcp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/playground/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | 3 | -------------------------------------------------------------------------------- /examples/x402/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/codemode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/tictactoe/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/x402-mcp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | 3 | -------------------------------------------------------------------------------- /openai-sdk/basic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /site/ai-playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/cross-domain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/mcp-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/mcp-worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=your_openai_api_key_here 2 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/hono-agents/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/mcp-elicitation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/mcp-worker-authenticated/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode", "biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /openai-sdk/basic/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/openai-sdk/basic/favicon.ico -------------------------------------------------------------------------------- /site/agents/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/agents/public/favicon.ico -------------------------------------------------------------------------------- /examples/a2a/src/express-alias.js: -------------------------------------------------------------------------------- 1 | // blank alias to avoid vite trying to bundle express 2 | export default {}; 3 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/openai-sdk/handoffs/favicon.ico -------------------------------------------------------------------------------- /site/agents/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/codemode/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/examples/codemode/public/favicon.ico -------------------------------------------------------------------------------- /examples/playground/src/model.ts: -------------------------------------------------------------------------------- 1 | import { openai } from "@ai-sdk/openai"; 2 | 3 | export const model = openai("gpt-4o"); 4 | -------------------------------------------------------------------------------- /examples/tictactoe/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/examples/tictactoe/public/favicon.ico -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/openai-sdk/llm-as-a-judge/favicon.ico -------------------------------------------------------------------------------- /site/ai-playground/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/ai-playground/public/favicon.ico -------------------------------------------------------------------------------- /examples/cross-domain/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/examples/cross-domain/public/favicon.ico -------------------------------------------------------------------------------- /examples/playground/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/examples/playground/public/favicon.ico -------------------------------------------------------------------------------- /guides/anthropic-patterns/.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | AI_GATEWAY_TOKEN= 3 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/openai-sdk/human-in-the-loop/favicon.ico -------------------------------------------------------------------------------- /examples/email-agent/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src/**/*", "test-mail.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/agents/src/cli/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { createCli } from "./create"; 4 | 5 | void createCli().parse(); 6 | -------------------------------------------------------------------------------- /site/agents/src/fonts/InterVariable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/agents/src/fonts/InterVariable.woff2 -------------------------------------------------------------------------------- /examples/mcp-elicitation/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/examples/mcp-elicitation/public/favicon.ico -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/favicon.ico -------------------------------------------------------------------------------- /guides/human-in-the-loop/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/human-in-the-loop/public/favicon.ico -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/openai-sdk/call-my-agent/public/favicon.ico -------------------------------------------------------------------------------- /site/agents/public/fonts/InterVariable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/agents/public/fonts/InterVariable.woff2 -------------------------------------------------------------------------------- /examples/mcp-client/.dev.vars.example: -------------------------------------------------------------------------------- 1 | # Optional: Override the auto-detected host (defaults to request origin) 2 | # HOST=http://localhost:5173 3 | -------------------------------------------------------------------------------- /packages/agents/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["src/tests/**/*.ts", "src/e2e/**/*.ts"], 3 | "extends": "../../tsconfig.base.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2021" 4 | }, 5 | "extends": "../../tsconfig.base.json" 6 | } 7 | -------------------------------------------------------------------------------- /site/agents/src/fonts/InterVariable-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/agents/src/fonts/InterVariable-Italic.woff2 -------------------------------------------------------------------------------- /site/agents/public/fonts/InterVariable-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/site/agents/public/fonts/InterVariable-Italic.woff2 -------------------------------------------------------------------------------- /.mcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "agents": { 4 | "type": "http", 5 | "url": "https://agents.cloudflare.com/mcp" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/mcp-elicitation/README.md: -------------------------------------------------------------------------------- 1 | # MCP Elicitation Demo 2 | 3 | This is a MCP server example that shows how to use elicitation support using the Agents SDK. 4 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/flows/02 routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/flows/02 routing.png -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/flows/03 parallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/flows/03 parallel.png -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/flows/05 evaluator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/flows/05 evaluator.png -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/README.md: -------------------------------------------------------------------------------- 1 | # Call My Agent 2 | 3 | Let's make an agent that you can make a phone call to! Powerd by the OpenAI agents sdk and twilio. 4 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/flows/01 sequential.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/flows/01 sequential.png -------------------------------------------------------------------------------- /guides/anthropic-patterns/public/flows/04 orchestrator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/agents/main/guides/anthropic-patterns/public/flows/04 orchestrator.png -------------------------------------------------------------------------------- /examples/cross-domain/env.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Cloudflare { 2 | interface Env { 3 | MyAgent: DurableObjectNamespace; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /site/agents/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | import tailwindcss from "@tailwindcss/postcss"; 2 | 3 | const config = { 4 | plugins: [tailwindcss] 5 | }; 6 | 7 | export default config; 8 | -------------------------------------------------------------------------------- /site/agents/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"] 4 | }; 5 | -------------------------------------------------------------------------------- /packages/agents/evals/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | setupFiles: ["dotenv/config"] 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /site/agents/src/components/gsap.ts: -------------------------------------------------------------------------------- 1 | import { gsap } from "gsap"; 2 | import { useGSAP } from "@gsap/react"; 3 | 4 | gsap.registerPlugin(useGSAP); 5 | 6 | export { gsap, useGSAP }; 7 | -------------------------------------------------------------------------------- /examples/cross-domain/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | export default defineConfig({ 5 | plugins: [react()] 6 | }); 7 | -------------------------------------------------------------------------------- /openai-sdk/basic/src/client.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | 3 | const root = createRoot(document.getElementById("root")!); 4 | 5 | root.render(
Hello World
); 6 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/src/client.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | 3 | const root = createRoot(document.getElementById("root")!); 4 | 5 | root.render(
Hello World
); 6 | -------------------------------------------------------------------------------- /site/ai-playground/src/client.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom/client"; 2 | import App from "./app"; 3 | import "./index.css"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render(); 6 | -------------------------------------------------------------------------------- /examples/mcp/src/client.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | 3 | function App() { 4 | return
Hello World
; 5 | } 6 | 7 | createRoot(document.getElementById("root")!).render(); 8 | -------------------------------------------------------------------------------- /examples/mcp/src/svg.d.ts: -------------------------------------------------------------------------------- 1 | // vite will already convert svg to base64 2 | // but we add this to make typescript happy 3 | 4 | declare module "*.svg" { 5 | const content: string; 6 | export default content; 7 | } 8 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | import App from "./client"; 3 | 4 | const root = createRoot(document.getElementById("root")!); 5 | root.render(); 6 | -------------------------------------------------------------------------------- /packages/agents/src/cli-tests/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | environment: "node", 6 | clearMocks: true 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /examples/playground/src/agents/stateful.ts: -------------------------------------------------------------------------------- 1 | import { Agent } from "agents"; 2 | export class Stateful extends Agent { 3 | initialState = { 4 | color: "#3B82F6", 5 | counter: 0, 6 | text: "" 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.txt" { 2 | const content: string; 3 | export default content; 4 | } 5 | 6 | declare module "*.txt?raw" { 7 | const content: string; 8 | export default content; 9 | } 10 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/src/client.tsx: -------------------------------------------------------------------------------- 1 | import "./styles.css"; 2 | import { createRoot } from "react-dom/client"; 3 | import App from "./app"; 4 | 5 | const root = createRoot(document.getElementById("root")!); 6 | 7 | root.render(); 8 | -------------------------------------------------------------------------------- /.github/changeset-publish.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from "node:child_process"; 2 | 3 | execSync("npx tsx ./.github/resolve-workspace-versions.ts", { 4 | stdio: "inherit" 5 | }); 6 | execSync("npx changeset publish", { 7 | stdio: "inherit" 8 | }); 9 | -------------------------------------------------------------------------------- /examples/mcp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MCP Example 5 | 6 | 7 |
8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Playground 5 | 6 | 7 |
8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/tictactoe/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), cloudflare()] 7 | }); 8 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/client.tsx: -------------------------------------------------------------------------------- 1 | // import { hydrateRoot } from "react-dom/client"; 2 | import { createRoot } from "react-dom/client"; 3 | import App from "./app"; 4 | 5 | const root = createRoot(document.getElementById("app")!); 6 | root.render(); 7 | -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), cloudflare()] 7 | }); 8 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Human in the Loop 5 | 6 | 7 |
8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /examples/mcp-worker/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-10-08", 3 | "compatibility_flags": ["nodejs_compat"], 4 | "main": "src/index.ts", 5 | "name": "mcp-worker", 6 | "observability": { 7 | "logs": { 8 | "enabled": true 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /openai-sdk/pizzaz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-pizzaz-app", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev" 8 | }, 9 | "dependencies": { 10 | "agents": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/agents/src/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "@cloudflare/workers-types/experimental", 5 | "@cloudflare/vitest-pool-workers" 6 | ] 7 | }, 8 | "extends": "../../../../tsconfig.base.json", 9 | "include": ["./**/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /examples/mcp/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), cloudflare()], 7 | server: { 8 | port: 5174 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /examples/x402-mcp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "keywords": [], 4 | "name": "@cloudflare/agents-x402-mcp-example", 5 | "private": true, 6 | "scripts": { 7 | "dev": "wrangler dev", 8 | "types": "wrangler types --include-runtime false" 9 | }, 10 | "type": "module" 11 | } 12 | -------------------------------------------------------------------------------- /examples/tictactoe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tic Tac Toe 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /site/agents/env.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Generated by Wrangler by running `wrangler types env.d.ts --include-runtime false` (hash: 83be826bfd14e0006039e186e1b11835) 3 | declare namespace Cloudflare { 4 | interface Env { 5 | DOCS_KV: KVNamespace; 6 | } 7 | } 8 | interface Env extends Cloudflare.Env {} 9 | -------------------------------------------------------------------------------- /examples/mcp-client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test MCP client 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /openai-sdk/basic/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import devtools from "vite-plugin-devtools-json"; 5 | 6 | export default defineConfig({ 7 | plugins: [devtools(), cloudflare(), react()] 8 | }); 9 | -------------------------------------------------------------------------------- /examples/cross-domain/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test cross domain 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/mcp-elicitation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Matt Carey ", 3 | "keywords": [], 4 | "name": "@cloudflare/agents-mcp-elicitation", 5 | "private": true, 6 | "scripts": { 7 | "deploy": "wrangler deploy", 8 | "dev": "wrangler dev" 9 | }, 10 | "type": "module" 11 | } 12 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), cloudflare()], 7 | server: { 8 | port: 3000 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Call My Agent 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import devtools from "vite-plugin-devtools-json"; 5 | 6 | export default defineConfig({ 7 | plugins: [devtools(), cloudflare(), react()] 8 | }); 9 | -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import devtools from "vite-plugin-devtools-json"; 5 | 6 | export default defineConfig({ 7 | plugins: [devtools(), cloudflare(), react()] 8 | }); 9 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import devtools from "vite-plugin-devtools-json"; 5 | 6 | export default defineConfig({ 7 | plugins: [devtools(), cloudflare(), react()] 8 | }); 9 | -------------------------------------------------------------------------------- /examples/a2a/README.md: -------------------------------------------------------------------------------- 1 | # A2A demo 2 | 3 | A minimal example showing an `A2A` running in Wrangler. 4 | 5 | ## Instructions 6 | 7 | ```sh 8 | npm install 9 | npm start 10 | ``` 11 | 12 | You should have the A2A agent running on http://localhost:5173. Navigate to http://localhost:5173/.well-known/agent.json to see the agent card. 13 | -------------------------------------------------------------------------------- /examples/tictactoe/README.md: -------------------------------------------------------------------------------- 1 | # Tic Tac Toe 2 | 3 | A simple demo showing a smart agent playing Tic Tac Toe against itself. 4 | 5 | ## Quick Start 6 | 7 | Copy `.dev.vars.example` to `.dev.vars` and fill in your OpenAI API key. 8 | 9 | ```bash 10 | npm i && npm start 11 | ``` 12 | 13 | Vist http://localhost:5174 to see the agent play. 14 | -------------------------------------------------------------------------------- /examples/mcp-worker-authenticated/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcp-worker-authenticated", 3 | "main": "src/index.ts", 4 | "compatibility_flags": ["nodejs_compat"], 5 | "compatibility_date": "2025-10-08", 6 | "kv_namespaces": [ 7 | { 8 | "binding": "OAUTH_KV", 9 | "id": "your-kv-namespace-id" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/agents/src/mcp/client-storage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a row in the cf_agents_mcp_servers table 3 | */ 4 | export type MCPServerRow = { 5 | id: string; 6 | name: string; 7 | server_url: string; 8 | client_id: string | null; 9 | auth_url: string | null; 10 | callback_url: string; 11 | server_options: string | null; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/mcp-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-mcp-client-example", 3 | "type": "module", 4 | "private": true, 5 | "author": "", 6 | "scripts": { 7 | "deploy": "vite build && wrangler deploy", 8 | "start": "vite dev" 9 | }, 10 | "dependencies": { 11 | "nanoid": "^5.1.6" 12 | }, 13 | "keywords": [] 14 | } 15 | -------------------------------------------------------------------------------- /examples/codemode/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), cloudflare()], 7 | define: { 8 | __filename: "'index.ts'" 9 | }, 10 | build: { 11 | minify: true 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /examples/codemode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Codemode Demo 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/tictactoe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A simple demo showing a smart agent playing Tic Tac Toe against a human.", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-tictactoe", 7 | "private": true, 8 | "scripts": { 9 | "start": "vite dev" 10 | }, 11 | "type": "module", 12 | "version": "0.0.0" 13 | } 14 | -------------------------------------------------------------------------------- /packages/agents/evals/README.md: -------------------------------------------------------------------------------- 1 | ## evals for core agent functionality 2 | 3 | setup a .env file with (any of) the following: 4 | 5 | ``` 6 | OPENAI_API_KEY= 7 | GOOGLE_GENERATIVE_AI_API_KEY= 8 | ANTHROPIC_API_KEY= 9 | ``` 10 | 11 | Choose a model in `src/scheduling.eval.ts` 12 | 13 | Then run the evals with `npx evalite` 14 | -------------------------------------------------------------------------------- /examples/codemode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-codemode-example", 3 | "author": "Sunil Pai ", 4 | "type": "module", 5 | "keywords": [], 6 | "private": true, 7 | "scripts": { 8 | "start": "vite dev", 9 | "types": "wrangler types env.d.ts --include-runtime false", 10 | "deploy": "vite build && wrangler deploy" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import { viteSingleFile } from "vite-plugin-singlefile"; 5 | 6 | export default defineConfig({ 7 | plugins: [react(), cloudflare(), viteSingleFile()], 8 | build: { 9 | minify: false 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "Human in the Loop", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-human-in-the-loop", 7 | "private": true, 8 | "scripts": { 9 | "deploy": "vite build && wrangler deploy", 10 | "start": "vite dev" 11 | }, 12 | "type": "module", 13 | "version": "0.0.0" 14 | } 15 | -------------------------------------------------------------------------------- /examples/cross-domain/README.md: -------------------------------------------------------------------------------- 1 | # Cross-Domain Communication Demo 2 | 3 | A simple demo showing WebSocket and HTTP communication between a React client and Cloudflare Worker server, when running on different domains. tl;dr - make sure you pass `cors: true` to routeAgentRequest. 4 | 5 | ## Quick Start 6 | 7 | Run the front end and agents server: 8 | 9 | ```bash 10 | npm i && npm start 11 | ``` 12 | -------------------------------------------------------------------------------- /examples/mcp-client/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | react(), 8 | cloudflare({ 9 | // ensure that we can run two instances of the dev server 10 | inspectorPort: 9230 11 | }) 12 | ] 13 | }); 14 | -------------------------------------------------------------------------------- /examples/mcp-worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-mcp-worker", 3 | "description": "The simplest way to run a stateless MCP Server on Cloudflare", 4 | "author": "Matt Carey ", 5 | "version": "0.0.1", 6 | "private": true, 7 | "type": "module", 8 | "scripts": { 9 | "dev": "wrangler dev", 10 | "deploy": "wrangler deploy" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /site/agents/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/agents/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/mcp/env.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Generated by Wrangler by running `wrangler types env.d.ts --include-runtime false` (hash: 3b0868993189c509ce2a638b2579e43e) 3 | declare namespace Cloudflare { 4 | interface GlobalProps { 5 | mainModule: typeof import("./src/server"); 6 | durableNamespaces: "MyMCP"; 7 | } 8 | interface Env {} 9 | } 10 | interface Env extends Cloudflare.Env {} 11 | -------------------------------------------------------------------------------- /packages/agents/src/react-tests/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | browser: { 6 | enabled: true, 7 | instances: [ 8 | { 9 | browser: "chromium", 10 | headless: true 11 | } 12 | ], 13 | provider: "playwright" 14 | }, 15 | clearMocks: true 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /examples/x402/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "dependencies": { 4 | "hono": "^4.10.7", 5 | "x402-fetch": "^0.7.3", 6 | "x402-hono": "^0.7.3" 7 | }, 8 | "keywords": [], 9 | "name": "@cloudflare/agents-x402-example", 10 | "private": true, 11 | "scripts": { 12 | "dev": "wrangler dev", 13 | "types": "wrangler types --include-runtime false" 14 | }, 15 | "type": "module" 16 | } 17 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { "repo": "cloudflare/agents" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "public", 11 | "baseBranch": "main", 12 | "updateInternalDependencies": "patch", 13 | "ignore": ["@cloudflare/agents-*"] 14 | } 15 | -------------------------------------------------------------------------------- /examples/mcp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "dependencies": { 4 | "mcp-remote": "^0.1.31" 5 | }, 6 | "keywords": [], 7 | "name": "@cloudflare/agents-mcp-example", 8 | "private": true, 9 | "scripts": { 10 | "start": "concurrently \"npx @modelcontextprotocol/inspector\" \"vite dev\" --kill-others", 11 | "types": "wrangler types env.d.ts --include-runtime false" 12 | }, 13 | "type": "module" 14 | } 15 | -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "LLM as a Judge example with OpenAI ⨉ Cloudflare Agents", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-openai-llm-as-a-judge", 7 | "private": true, 8 | "scripts": { 9 | "clean": "rm -rf .wrangler node_modules/.vite", 10 | "start": "vite dev" 11 | }, 12 | "type": "module", 13 | "version": "0.0.0" 14 | } 15 | -------------------------------------------------------------------------------- /examples/a2a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-a2a-example", 3 | "private": true, 4 | "author": "Matt Carey ", 5 | "dependencies": { 6 | "@a2a-js/sdk": "^0.2.2", 7 | "hono": "^4.10.7" 8 | }, 9 | "keywords": [], 10 | "scripts": { 11 | "cli": "npx tsx src/cli.ts", 12 | "start": "vite dev", 13 | "deploy": "vite build && wrangler deploy" 14 | }, 15 | "type": "module" 16 | } 17 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "Human in the loop example with OpenAI ⨉ Cloudflare Agents", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-openai-human-in-the-loop", 7 | "private": true, 8 | "scripts": { 9 | "clean": "rm -rf .wrangler node_modules/.vite", 10 | "start": "vite dev" 11 | }, 12 | "type": "module", 13 | "version": "0.0.0" 14 | } 15 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | - get started 2 | - add to an existing project 3 | - routing 4 | - human in the loop 5 | - control flow 6 | - state 7 | - sync-engine 8 | - ai-sdk 9 | - tools 10 | - other stacks 11 | - http/ws 12 | - email 13 | - a/v 14 | - scheduling 15 | - queue 16 | - pause/resume 17 | - memory 18 | - evals 19 | - observability 20 | - connect anything 21 | - self hosting 22 | - how is this different from durable objects? 23 | - resources / read more 24 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Anthropic Patterns 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /site/agents/src/components/links.ts: -------------------------------------------------------------------------------- 1 | export const withUtm = (link: string) => { 2 | const url = new URL(link); 3 | url.searchParams.append("utm_content", "agents.cloudflare.com"); 4 | return url.toString(); 5 | }; 6 | 7 | export const DASHBOARD_HREF = withUtm( 8 | "https://dash.cloudflare.com/?to=/:account/workers-and-pages/create" 9 | ); 10 | export const AGENTS_DOCS_HREF = withUtm( 11 | "https://developers.cloudflare.com/agents/" 12 | ); 13 | -------------------------------------------------------------------------------- /site/agents/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "name": "agents-site", 4 | "compatibility_date": "2025-10-25", 5 | "main": "src/server/index.ts", 6 | "compatibility_flags": ["nodejs_compat"], 7 | "assets": { 8 | "directory": "dist" 9 | }, 10 | "kv_namespaces": [ 11 | { 12 | "binding": "DOCS_KV", 13 | "id": "c438ca2bb9d84bbabb45ae5ca29dcce5" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A basic OpenAI ⨉ Cloudflare Agents example, duplicate this repo when making more examples", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-openai-handoffs", 7 | "private": true, 8 | "scripts": { 9 | "clean": "rm -rf .wrangler node_modules/.vite", 10 | "start": "vite dev" 11 | }, 12 | "type": "module", 13 | "version": "0.0.0" 14 | } 15 | -------------------------------------------------------------------------------- /examples/mcp-worker/README.md: -------------------------------------------------------------------------------- 1 | # MCP Worker Example 2 | 3 | This example demonstrates how to use `createMcpHandler` to create an unauthenticated stateless MCP server. 4 | 5 | This is THE simplest way to get started with MCP on Cloudflare. 6 | 7 | ## Usage 8 | 9 | ```bash 10 | npm install 11 | npm run dev 12 | ``` 13 | 14 | ## Testing 15 | 16 | You can test the MCP server using the MCP Inspector or any MCP client that supports the `streamable-http` transport. 17 | -------------------------------------------------------------------------------- /examples/mcp/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-03-14", 3 | "compatibility_flags": ["nodejs_compat"], 4 | "durable_objects": { 5 | "bindings": [ 6 | { 7 | "class_name": "MyMCP", 8 | "name": "MyMCP" 9 | } 10 | ] 11 | }, 12 | "main": "src/server.ts", 13 | "migrations": [ 14 | { 15 | "new_sqlite_classes": ["MyMCP"], 16 | "tag": "v1" 17 | } 18 | ], 19 | "name": "mcp-agent-demo" 20 | } 21 | -------------------------------------------------------------------------------- /openai-sdk/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Basic OpenAI ⨉ Cloudflare Agents Example 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /site/ai-playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import tailwindcss from "@tailwindcss/vite"; 3 | import react from "@vitejs/plugin-react"; 4 | import { defineConfig } from "vite"; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | react(), 9 | tailwindcss(), 10 | cloudflare({ 11 | // ensure that we can run two instances of the dev server 12 | inspectorPort: 9230 13 | }) 14 | ] 15 | }); 16 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Basic OpenAI ⨉ Cloudflare Agents Example 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/cross-domain/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-03-14", 3 | "compatibility_flags": ["nodejs_compat"], 4 | "durable_objects": { 5 | "bindings": [ 6 | { 7 | "class_name": "MyAgent", 8 | "name": "MyAgent" 9 | } 10 | ] 11 | }, 12 | "main": "src/server.ts", 13 | "migrations": [ 14 | { 15 | "new_sqlite_classes": ["MyAgent"], 16 | "tag": "v1" 17 | } 18 | ], 19 | "name": "cross-domain" 20 | } 21 | -------------------------------------------------------------------------------- /guides/human-in-the-loop/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "human-in-the-loop" 2 | main = "./src/server.ts" 3 | compatibility_date = "2025-02-21" 4 | compatibility_flags = [ 5 | "nodejs_compat", 6 | "nodejs_compat_populate_process_env", 7 | ] 8 | 9 | assets = { directory = "public" } 10 | 11 | 12 | [[durable_objects.bindings]] 13 | name = "HumanInTheLoop" 14 | class_name = "HumanInTheLoop" 15 | 16 | [[migrations]] 17 | tag = "v1" 18 | new_sqlite_classes = ["HumanInTheLoop"] 19 | -------------------------------------------------------------------------------- /openai-sdk/pizzaz/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pizzaz-mcp", 3 | "main": "src/index.ts", 4 | "compatibility_date": "2025-08-26", 5 | "compatibility_flags": ["nodejs_compat"], 6 | "durable_objects": { 7 | "bindings": [ 8 | { 9 | "name": "MCP_OBJECT", 10 | "class_name": "PizzazMcp" 11 | } 12 | ] 13 | }, 14 | "migrations": [ 15 | { 16 | "tag": "v1", 17 | "new_sqlite_classes": ["PizzazMcp"] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-05-05", 3 | "compatibility_flags": ["nodejs_compat"], 4 | "durable_objects": { 5 | "bindings": [ 6 | { 7 | "class_name": "MyAgent", 8 | "name": "MyAgent" 9 | } 10 | ] 11 | }, 12 | "main": "src/server.ts", 13 | "migrations": [ 14 | { 15 | "new_sqlite_classes": ["MyAgent"], 16 | "tag": "v1" 17 | } 18 | ], 19 | "name": "call-my-agent" 20 | } 21 | -------------------------------------------------------------------------------- /examples/email-agent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-email-agent", 3 | "version": "0.0.0", 4 | "description": "Email routing agent example", 5 | "private": true, 6 | "type": "module", 7 | "scripts": { 8 | "deploy": "wrangler deploy", 9 | "start": "wrangler dev", 10 | "test-email": "tsx test-mail.ts" 11 | }, 12 | "dependencies": { 13 | "postal-mime": "^2.6.1" 14 | }, 15 | "keywords": [], 16 | "license": "ISC", 17 | "author": "" 18 | } 19 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "dependencies": { 4 | "nanoid": "^5.1.6" 5 | }, 6 | "description": "The anthropic patterns, implemented with cloudflare agents", 7 | "keywords": [], 8 | "license": "ISC", 9 | "name": "@cloudflare/agents-anthropic-patterns", 10 | "private": true, 11 | "scripts": { 12 | "deploy": "vite build && wrangler deploy", 13 | "start": "vite dev" 14 | }, 15 | "type": "module", 16 | "version": "0.0.0" 17 | } 18 | -------------------------------------------------------------------------------- /examples/cross-domain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A simple demo showing WebSocket and HTTP communication between a React client and Cloudflare Worker server, when running on different domains.", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-cross-domain", 7 | "private": true, 8 | "scripts": { 9 | "start": "concurrently \"vite dev\" \"wrangler dev\" --kill-others" 10 | }, 11 | "type": "module", 12 | "version": "0.0.0" 13 | } 14 | -------------------------------------------------------------------------------- /examples/mcp-worker-authenticated/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-authenticated-mcp-worker", 3 | "description": "The simplest way to run a stateless authenticated MCP Server on Cloudflare", 4 | "author": "Matt Carey ", 5 | "version": "0.0.1", 6 | "private": true, 7 | "type": "module", 8 | "scripts": { 9 | "dev": "wrangler dev", 10 | "deploy": "wrangler deploy" 11 | }, 12 | "dependencies": { 13 | "hono": "^4.10.7" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/a2a/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { cloudflare } from "@cloudflare/vite-plugin"; 4 | import path from "node:path"; 5 | 6 | export default defineConfig({ 7 | resolve: { 8 | alias: { 9 | // a2a-js/sdk has a dependency on express, which vite tries to bundle. This alias prevents that. 10 | express: path.resolve(__dirname, "./src/express-alias.js") 11 | } 12 | }, 13 | plugins: [react(), cloudflare()] 14 | }); 15 | -------------------------------------------------------------------------------- /site/ai-playground/src/models.ts: -------------------------------------------------------------------------------- 1 | // these fields exist on the AiModelsSearchObject type, but are not typed in the workers-types package. We should fix it there, but for now we'll add them here. 2 | export type Model = AiModelsSearchObject & { 3 | created_at: number; 4 | finetunes?: FineTune[]; 5 | }; 6 | 7 | export type FineTune = { 8 | id: string; 9 | name: string; 10 | description: string; 11 | created_at: string; 12 | modified_at: string; 13 | public: number; 14 | model: keyof AiModels; 15 | }; 16 | -------------------------------------------------------------------------------- /examples/playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "dependencies": { 4 | "cronstrue": "^3.9.0", 5 | "nanoid": "^5.1.6" 6 | }, 7 | "description": "", 8 | "keywords": [], 9 | "license": "ISC", 10 | "name": "@cloudflare/agents-playground", 11 | "private": true, 12 | "scripts": { 13 | "deploy": "vite build && wrangler deploy", 14 | "types": "wrangler types env.d.ts --include-runtime false", 15 | "start": "vite dev" 16 | }, 17 | "type": "module", 18 | "version": "0.0.0" 19 | } 20 | -------------------------------------------------------------------------------- /openai-sdk/call-my-agent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A simple agent that can receive phone calls and respond to them.", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-openai-call-my-agent", 7 | "private": true, 8 | "scripts": { 9 | "clean": "rm -rf dist .wrangler node_modules/.vite node_modules/.vite-temp", 10 | "deploy": "vite build && wrangler deploy", 11 | "start": "vite dev" 12 | }, 13 | "type": "module", 14 | "version": "0.0.0" 15 | } 16 | -------------------------------------------------------------------------------- /examples/mcp/src/mcp-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MCP 7 | 8 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Generated by Wrangler by running `wrangler types --include-runtime false` (hash: 8f9c651072ec4f30c93c6c12a7aedf3f) 3 | declare namespace Cloudflare { 4 | interface GlobalProps { 5 | mainModule: typeof import("./src/index"); 6 | durableNamespaces: "ChessGame"; 7 | } 8 | interface Env { 9 | CHESS: DurableObjectNamespace; 10 | ASSETS: Fetcher; 11 | } 12 | } 13 | interface Env extends Cloudflare.Env {} 14 | -------------------------------------------------------------------------------- /packages/agents/src/mcp/auth-context.ts: -------------------------------------------------------------------------------- 1 | import { AsyncLocalStorage } from "node:async_hooks"; 2 | 3 | export interface McpAuthContext { 4 | props: Record; 5 | } 6 | 7 | const authContextStorage = new AsyncLocalStorage(); 8 | 9 | export function getMcpAuthContext(): McpAuthContext | undefined { 10 | return authContextStorage.getStore(); 11 | } 12 | 13 | export function runWithAuthContext(context: McpAuthContext, fn: () => T): T { 14 | return authContextStorage.run(context, fn); 15 | } 16 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A resumable real-time AI streaming chat with automatic reconnection and history replay using Durable Objects", 4 | "license": "ISC", 5 | "name": "@cloudflare/agents-resumable-stream-chat", 6 | "private": true, 7 | "scripts": { 8 | "deploy": "vite build && wrangler deploy", 9 | "types": "wrangler types env.d.ts --include-runtime false", 10 | "start": "vite dev" 11 | }, 12 | "type": "module", 13 | "version": "0.0.0" 14 | } 15 | -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Marketing Agent with LLM As a Judge 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/a2a/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "name": "a2a-agent-demo", 4 | "main": "src/server.ts", 5 | "compatibility_date": "2025-03-14", 6 | "compatibility_flags": ["nodejs_compat"], 7 | 8 | "durable_objects": { 9 | "bindings": [ 10 | { 11 | "class_name": "MyA2A", 12 | "name": "MyA2A" 13 | } 14 | ] 15 | }, 16 | "migrations": [ 17 | { 18 | "new_sqlite_classes": ["MyA2A"], 19 | "tag": "v1" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Weather Agent with Human-in-the-Loop 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /examples/email-agent/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "name": "agents-email-agent", 4 | "main": "src/index.ts", 5 | "compatibility_date": "2024-12-01", 6 | "compatibility_flags": ["nodejs_compat"], 7 | "durable_objects": { 8 | "bindings": [ 9 | { 10 | "name": "EmailAgent", 11 | "class_name": "EmailAgent" 12 | } 13 | ] 14 | }, 15 | "migrations": [ 16 | { 17 | "tag": "v1", 18 | "new_sqlite_classes": ["EmailAgent"] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /openai-sdk/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "description": "A basic OpenAI ⨉ Cloudflare Agents example, duplicate this repo when making more examples", 4 | "keywords": [], 5 | "license": "ISC", 6 | "name": "@cloudflare/agents-openai-basic", 7 | "private": true, 8 | "scripts": { 9 | "clean": "rm -rf .wrangler node_modules/.vite", 10 | "start": "npm run clean && vite dev", 11 | "types": "wrangler types env.d.ts --include-runtime false --strict-vars false" 12 | }, 13 | "type": "module", 14 | "version": "0.0.0" 15 | } 16 | -------------------------------------------------------------------------------- /site/ai-playground/src/index.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @source "../../../node_modules/streamdown/dist/index.js"; 4 | 5 | html, 6 | body, 7 | #root { 8 | width: 100%; 9 | height: 100%; 10 | margin: 0; 11 | } 12 | 13 | .bg-ai { 14 | background-image: linear-gradient(75deg, #901475, #ce2f55, #ff6633); 15 | } 16 | 17 | .bg-ai-loop { 18 | background-image: linear-gradient( 19 | 75deg, 20 | #901475, 21 | #ce2f55, 22 | #ff6633, 23 | #ce2f55, 24 | #901475 25 | ); 26 | } 27 | 28 | button { 29 | cursor: pointer; 30 | } 31 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "compatibility_date": "2025-05-25", 4 | "compatibility_flags": ["nodejs_compat"], 5 | "durable_objects": { 6 | "bindings": [ 7 | { 8 | "class_name": "MyAgent", 9 | "name": "MyAgent" 10 | } 11 | ] 12 | }, 13 | "main": "./src/server.ts", 14 | "migrations": [ 15 | { 16 | "new_sqlite_classes": ["MyAgent"], 17 | "tag": "0.0.1" 18 | } 19 | ], 20 | "name": "handoffs-openai-cloudflare-agent" 21 | } 22 | -------------------------------------------------------------------------------- /examples/mcp-elicitation/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-03-14", 3 | "compatibility_flags": ["nodejs_compat"], 4 | "durable_objects": { 5 | "bindings": [ 6 | { 7 | "class_name": "MyAgent", 8 | "name": "MyAgent" 9 | } 10 | ] 11 | }, 12 | "main": "src/index.ts", 13 | "migrations": [ 14 | { 15 | "new_sqlite_classes": ["MyAgent"], 16 | "tag": "v1" 17 | } 18 | ], 19 | "name": "mcp-elicitation-demo", 20 | "observability": { 21 | "logs": { 22 | "enabled": true 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /openai-sdk/llm-as-a-judge/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "compatibility_date": "2025-07-01", 4 | "compatibility_flags": ["nodejs_compat"], 5 | "durable_objects": { 6 | "bindings": [ 7 | { 8 | "class_name": "MyAgent", 9 | "name": "MyAgent" 10 | } 11 | ] 12 | }, 13 | "main": "./src/server.ts", 14 | "migrations": [ 15 | { 16 | "new_sqlite_classes": ["MyAgent"], 17 | "tag": "0.0.1" 18 | } 19 | ], 20 | "name": "llm-as-a-judge-openai-cloudflare-agent" 21 | } 22 | -------------------------------------------------------------------------------- /openai-sdk/human-in-the-loop/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "compatibility_date": "2025-05-25", 4 | "compatibility_flags": ["nodejs_compat"], 5 | "durable_objects": { 6 | "bindings": [ 7 | { 8 | "class_name": "MyAgent", 9 | "name": "MyAgent" 10 | } 11 | ] 12 | }, 13 | "main": "./src/server.ts", 14 | "migrations": [ 15 | { 16 | "new_sqlite_classes": ["MyAgent"], 17 | "tag": "0.0.1" 18 | } 19 | ], 20 | "name": "human-in-the-loop-openai-cloudflare-agent" 21 | } 22 | -------------------------------------------------------------------------------- /examples/playground/src/server.ts: -------------------------------------------------------------------------------- 1 | import { routeAgentRequest } from "agents"; 2 | import { Chat } from "./agents/chat"; 3 | import { Rpc } from "./agents/rpc"; 4 | import { Scheduler } from "./agents/scheduler"; 5 | import { Stateful } from "./agents/stateful"; 6 | 7 | export { Scheduler, Stateful, Chat, Rpc }; 8 | 9 | export default { 10 | async fetch(request: Request, env: Env, _ctx: ExecutionContext) { 11 | return ( 12 | (await routeAgentRequest(request, env)) || 13 | new Response("Not found", { status: 404 }) 14 | ); 15 | } 16 | } satisfies ExportedHandler; 17 | -------------------------------------------------------------------------------- /examples/tictactoe/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "assets": { 3 | "directory": "public" 4 | }, 5 | "compatibility_date": "2025-03-14", 6 | "compatibility_flags": [ 7 | "nodejs_compat", 8 | "nodejs_compat_populate_process_env" 9 | ], 10 | "durable_objects": { 11 | "bindings": [ 12 | { 13 | "class_name": "TicTacToe", 14 | "name": "TicTacToe" 15 | } 16 | ] 17 | }, 18 | "main": "src/server.ts", 19 | "migrations": [ 20 | { 21 | "new_sqlite_classes": ["TicTacToe"], 22 | "tag": "v1" 23 | } 24 | ], 25 | "name": "tictactoe" 26 | } 27 | -------------------------------------------------------------------------------- /openai-sdk/basic/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "compatibility_date": "2025-05-25", 4 | "compatibility_flags": ["nodejs_compat"], 5 | "ai": { 6 | "binding": "AI" 7 | }, 8 | "durable_objects": { 9 | "bindings": [ 10 | { 11 | "class_name": "MyAgent", 12 | "name": "MyAgent" 13 | } 14 | ] 15 | }, 16 | "main": "./src/server.ts", 17 | "migrations": [ 18 | { 19 | "new_sqlite_classes": ["MyAgent"], 20 | "tag": "0.0.1" 21 | } 22 | ], 23 | "name": "basic-openai-cloudflare-agent" 24 | } 25 | -------------------------------------------------------------------------------- /examples/codemode/README.md: -------------------------------------------------------------------------------- 1 | # Codemode Demo 2 | 3 | This is a demo of the Codemode application. 4 | 5 | image 6 | 7 | ## Running the demo 8 | 9 | 1. Install dependencies in the root (`npm install`) 10 | 2. Navigate to `examples/codemode/` (that's here) 11 | 3. Build dependencies in the root (`npm run build`) 12 | 4. Create a `.env` file with your OpenAI API key (see `.env.example`) 13 | 5. Run `npm start` to start the development server 14 | 6. Visit `http://localhost:5173` to see the demo 15 | -------------------------------------------------------------------------------- /examples/playground/src/agents/rpc.ts: -------------------------------------------------------------------------------- 1 | import { Agent, type StreamingResponse, callable } from "agents"; 2 | 3 | export class Rpc extends Agent { 4 | @callable() 5 | async test() { 6 | return "Hello, world!"; 7 | } 8 | 9 | @callable({ streaming: true }) 10 | async testStreaming(stream: StreamingResponse) { 11 | for (let i = 0; i < 10; i++) { 12 | stream.send(`Hello, world! ${i}`); 13 | await new Promise((resolve) => setTimeout(resolve, 1000)); 14 | } 15 | stream.end("Done"); 16 | } 17 | 18 | @callable() 19 | async destroyAgent() { 20 | await this.destroy(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/agents/src/mcp/types.ts: -------------------------------------------------------------------------------- 1 | export type MaybePromise = T | Promise; 2 | export type MaybeConnectionTag = { role: string } | undefined; 3 | 4 | export type BaseTransportType = "sse" | "streamable-http"; 5 | export type TransportType = BaseTransportType | "auto"; 6 | 7 | export interface CORSOptions { 8 | origin?: string; 9 | methods?: string; 10 | headers?: string; 11 | maxAge?: number; 12 | exposeHeaders?: string; 13 | } 14 | 15 | export interface ServeOptions { 16 | binding?: string; 17 | corsOptions?: CORSOptions; 18 | transport?: BaseTransportType; 19 | jurisdiction?: DurableObjectJurisdiction; 20 | } 21 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/layout.tsx: -------------------------------------------------------------------------------- 1 | // let's use this again when we have SSR 2 | 3 | export function Layout({ children }: { children: React.ReactNode }) { 4 | return ( 5 | 6 | 7 | 8 | 9 | Anthropic Patterns 10 | 11 | 12 | 13 |
{children}
14 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/playground/src/agents/chat.ts: -------------------------------------------------------------------------------- 1 | import { AIChatAgent } from "agents/ai-chat-agent"; 2 | import { 3 | convertToModelMessages, 4 | streamText, 5 | createUIMessageStreamResponse, 6 | createUIMessageStream, 7 | type StreamTextOnFinishCallback 8 | } from "ai"; 9 | import { model } from "../model"; 10 | 11 | export class Chat extends AIChatAgent { 12 | async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) { 13 | const stream = createUIMessageStream({ 14 | execute: async ({ writer }) => { 15 | const result = streamText({ 16 | messages: convertToModelMessages(this.messages), 17 | model, 18 | onFinish 19 | }); 20 | 21 | writer.merge(result.toUIMessageStream()); 22 | } 23 | }); 24 | 25 | return createUIMessageStreamResponse({ stream }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/version-script.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import { execSync } from "node:child_process"; 3 | async function main() { 4 | try { 5 | console.log("Getting current git hash..."); 6 | const stdout = execSync("git rev-parse --short HEAD").toString(); 7 | console.log("Git hash:", stdout.trim()); 8 | 9 | for (const path of [ 10 | "./packages/agents/package.json", 11 | "./packages/hono-agents/package.json" 12 | ]) { 13 | const packageJson = JSON.parse(fs.readFileSync(path, "utf-8")); 14 | packageJson.version = `0.0.0-${stdout.trim()}`; 15 | fs.writeFileSync(path, `${JSON.stringify(packageJson, null, 2)}\n`); 16 | } 17 | } catch (error) { 18 | console.error(error); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main().catch((err) => { 24 | // Build failures should fail 25 | console.error(err); 26 | process.exit(1); 27 | }); 28 | -------------------------------------------------------------------------------- /examples/mcp-worker/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createMcpHandler } from "agents/mcp"; 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 3 | import { z } from "zod"; 4 | 5 | type Env = {}; 6 | 7 | const server = new McpServer({ 8 | name: "Hello MCP Server", 9 | version: "1.0.0" 10 | }); 11 | 12 | server.registerTool( 13 | "hello", 14 | { 15 | description: "Returns a greeting message", 16 | inputSchema: { name: z.string().optional() } 17 | }, 18 | async ({ name }) => { 19 | return { 20 | content: [ 21 | { 22 | text: `Hello, ${name ?? "World"}!`, 23 | type: "text" 24 | } 25 | ] 26 | }; 27 | } 28 | ); 29 | 30 | export default { 31 | fetch: async (request: Request, env: Env, ctx: ExecutionContext) => { 32 | const handler = createMcpHandler(server); 33 | return handler(request, env, ctx); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /site/ai-playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-ai-playground", 3 | "type": "module", 4 | "private": true, 5 | "author": "AI Agents Team <1800-agents@cloudflare.com>", 6 | "scripts": { 7 | "start": "vite dev", 8 | "clean": "rm -rf .wrangler node_modules/.vite dist", 9 | "build": "npm run clean && vite build", 10 | "deploy": "npm run build && wrangler deploy --var HOST:https://playground.ai.cloudflare.com --domain playground.ai.cloudflare.com", 11 | "type-check": "tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "downshift": "^9.0.10", 15 | "nanoid": "^5.1.6", 16 | "react": "^19.2.0", 17 | "react-dom": "^19.2.0", 18 | "react-hotkeys-hook": "^5.2.1", 19 | "react-textarea-autosize": "^8.5.9", 20 | "streamdown": "^1.6.8", 21 | "workers-ai-provider": "^2.0.0", 22 | "zod": "^3.25.76" 23 | }, 24 | "keywords": [] 25 | } 26 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/README.md: -------------------------------------------------------------------------------- 1 | ![chess-app-screenshot](https://github.com/user-attachments/assets/8b2a36b7-5e2d-4645-95ad-16c81709a4e9) 2 | [Reference](https://developers.openai.com/apps-sdk/) 3 | 4 | # Multi-player Chess ChatGPT App 5 | 6 | Build a real-time multi-player chess game that runs on ChatGPT by using `McpAgent` to build your ChatGPT app and an `Agent` to be your remote game engine! 7 | 8 | The app also shows how you can call ChatGPT from within your app. You can always press the "Ask for help" button and ChatGPT will answer in your conversation with a proper strategy for you. 9 | 10 | It had never been easier to play chess with your friends with a tutor by your side! 11 | 12 | ## Requirements 13 | 14 | You'll need a ChatGPT developer account to be able to use ChatGPT apps (connectors). To do so, from ChatGPT go to **Settings -> Apps & Connectors -> Advanced Settings -> Developer mode ON**. 15 | -------------------------------------------------------------------------------- /site/ai-playground/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { UIMessage } from "ai"; 2 | import { isToolUIPart } from "ai"; 3 | 4 | /** 5 | * Clean up incomplete tool calls from messages before sending to API 6 | * Prevents API errors from interrupted or failed tool executions 7 | */ 8 | export function cleanupMessages(messages: UIMessage[]): UIMessage[] { 9 | return messages.filter((message) => { 10 | if (!message.parts) return true; 11 | 12 | // Filter out messages with incomplete tool calls 13 | const hasIncompleteToolCall = message.parts.some((part) => { 14 | if (!isToolUIPart(part)) return false; 15 | // Remove tool calls that are still streaming or awaiting input without results 16 | return ( 17 | part.state === "input-streaming" || 18 | (part.state === "input-available" && !part.output && !part.errorText) 19 | ); 20 | }); 21 | 22 | return !hasIncompleteToolCall; 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /patches/@changesets+cli+2.29.7.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/@changesets/cli/dist/changesets-cli.cjs.js b/node_modules/@changesets/cli/dist/changesets-cli.cjs.js 2 | index 53fc925..d888f84 100644 3 | --- a/node_modules/@changesets/cli/dist/changesets-cli.cjs.js 4 | +++ b/node_modules/@changesets/cli/dist/changesets-cli.cjs.js 5 | @@ -762,7 +762,9 @@ async function internalPublish(packageJson, opts, twoFactorState) { 6 | // Due to a super annoying issue in yarn, we have to manually override this env variable 7 | // See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633 8 | const envOverride = { 9 | - [scope ? `npm_config_${scope}:registry` : "npm_config_registry"]: registry 10 | + [scope ? `npm_config_${scope}:registry` : "npm_config_registry"]: registry, 11 | + // Don't pass through any npm auth tokens so that we use trusted publishers 12 | + NODE_AUTH_TOKEN: "", 13 | }; 14 | let { 15 | code, 16 | -------------------------------------------------------------------------------- /examples/x402-mcp/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Generated by Wrangler by running `wrangler types --include-runtime false` (hash: 2dbbed5c96990447ec3e12061d81530e) 3 | declare namespace Cloudflare { 4 | interface Env { 5 | SERVER_ADDRESS: "0xFa75d8F07BA244c29cbdb32fD3093D759857072E"; 6 | MCP_ADDRESS: string; 7 | CLIENT_TEST_PK: string; 8 | MCP_OBJECT: DurableObjectNamespace; 9 | PAY_AGENT: DurableObjectNamespace; 10 | } 11 | } 12 | interface Env extends Cloudflare.Env {} 13 | type StringifyValues> = { 14 | [Binding in keyof EnvType]: EnvType[Binding] extends string 15 | ? EnvType[Binding] 16 | : string; 17 | }; 18 | declare namespace NodeJS { 19 | interface ProcessEnv extends StringifyValues< 20 | Pick 21 | > {} 22 | } 23 | -------------------------------------------------------------------------------- /examples/playground/README.md: -------------------------------------------------------------------------------- 1 | # Agent Playground 2 | 3 | A collection of interactive examples demonstrating core agent capabilities. 4 | 5 | ## Running the Examples 6 | 7 | Copy `.dev.vars.example` to `.dev.vars` and fill in your OpenAI API key. 8 | 9 | ```bash 10 | # Install dependencies 11 | npm install 12 | 13 | # Start the development server 14 | npm start 15 | ``` 16 | 17 | Visit `localhost:5173` to explore the examples. 18 | 19 | ## Examples 20 | 21 | ### State Synchronization 22 | 23 | Demonstrates real-time state synchronization across multiple clients: 24 | 25 | - Counter with shared state 26 | - Text input synchronization 27 | - Color picker with live updates 28 | - Multi-window synchronization 29 | 30 | ### Temporal Patterns 31 | 32 | Shows how agents can schedule and manage tasks over time: 33 | 34 | - Immediate actions (10-second intervals) 35 | - Daily scheduled tasks 36 | - Cron-based scheduling 37 | - Future date scheduling 38 | -------------------------------------------------------------------------------- /licenses/README.md: -------------------------------------------------------------------------------- 1 | # License Files 2 | 3 | This directory contains the full license texts for third-party dependencies. 4 | 5 | ## File Naming Convention 6 | 7 | - `apache-2.0-[project-name].txt` - Apache 2.0 licenses 8 | - `mit-[project-name].txt` - MIT licenses 9 | - `bsd-[project-name].txt` - BSD licenses 10 | - `gpl-[project-name].txt` - GPL licenses 11 | - `other-[project-name].txt` - Other licenses 12 | 13 | ## Current Licenses 14 | 15 | - `mit-anthropic-mcp-ts-sdk.txt` - Anthropic MCP TS SDK (MIT) 16 | - `apache-2.0-coinbase-x402.txt` - Coinbase x402 (Apache 2.0) 17 | - `mit-ethanniser-x402-mcp.txt` - ethanniser/x402-mcp (MIT) 18 | - `apache-2.0-vercel-ai-sdk.txt` - Vercel AI SDK (Apache 2.0) 19 | 20 | ## Adding New Licenses 21 | 22 | 1. Add the full license text to this directory following the naming convention 23 | 2. Update `../THIRD_PARTY_LICENSES.md` with the new dependency 24 | 3. Update `../NOTICE` if required by the license terms 25 | -------------------------------------------------------------------------------- /site/agents/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | :root { 4 | --background: #ffffff; 5 | --foreground: #171717; 6 | } 7 | 8 | @theme inline { 9 | --color-background: var(--background); 10 | --color-foreground: var(--foreground); 11 | --font-mono: 12 | ui-monospace, Menlo, Monaco, "Segoe UI Mono", "Source Code Pro", 13 | "Fira Mono", monospace; 14 | } 15 | 16 | * { 17 | font-feature-settings: "ss02", "ss07", "ss08"; 18 | font-synthesis: none; 19 | } 20 | 21 | body { 22 | background: var(--background); 23 | color: var(--foreground); 24 | font-family: var(--font-sans); 25 | } 26 | 27 | .cursor { 28 | animation-name: blink; 29 | animation-duration: 1s; 30 | animation-iteration-count: infinite; 31 | animation-timing-function: steps(1); 32 | } 33 | 34 | @keyframes blink { 35 | 0% { 36 | opacity: 1; 37 | } 38 | 50% { 39 | opacity: 0; 40 | } 41 | 100% { 42 | opacity: 1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/playground/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "name": "playground", 4 | "main": "src/server.ts", 5 | "compatibility_date": "2025-02-19", 6 | "compatibility_flags": [ 7 | "nodejs_compat", 8 | "nodejs_compat_populate_process_env" 9 | ], 10 | "assets": { 11 | "binding": "ASSETS" 12 | }, 13 | "durable_objects": { 14 | "bindings": [ 15 | { 16 | "class_name": "Scheduler", 17 | "name": "Scheduler" 18 | }, 19 | { 20 | "class_name": "Stateful", 21 | "name": "Stateful" 22 | }, 23 | { 24 | "class_name": "Chat", 25 | "name": "Chat" 26 | }, 27 | { 28 | "class_name": "Rpc", 29 | "name": "Rpc" 30 | } 31 | ] 32 | }, 33 | "migrations": [ 34 | { 35 | "new_sqlite_classes": ["Scheduler", "Stateful", "Chat", "Rpc"], 36 | "tag": "v1" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /site/agents/src/components/_components/install-command.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from "react"; 2 | import { useTypedMessage } from "./chat"; 3 | import { useInView } from "framer-motion"; 4 | 5 | export function InstallCommand() { 6 | const ref = useRef(null); 7 | const [playing, setPlaying] = useState(false); 8 | const { visibleMessage, start } = useTypedMessage("npm i agents", { 9 | speed: 100, 10 | onDone: () => setPlaying(false) 11 | }); 12 | const inView = useInView(ref, { amount: 1, once: true }); 13 | 14 | useEffect(() => { 15 | if (inView) start(); 16 | }, [inView]); 17 | 18 | return ( 19 | 20 | $ {visibleMessage} 21 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /site/ai-playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | Workers AI LLM Playground 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/agents/scripts/build.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from "node:child_process"; 2 | import { build } from "tsdown"; 3 | 4 | async function main() { 5 | await build({ 6 | clean: true, 7 | dts: true, 8 | entry: [ 9 | "src/*.ts", 10 | "src/*.tsx", 11 | "src/cli/index.ts", 12 | "src/mcp/index.ts", 13 | "src/mcp/client.ts", 14 | "src/mcp/do-oauth-client-provider.ts", 15 | "src/mcp/x402.ts", 16 | "src/observability/index.ts", 17 | "src/codemode/ai.ts" 18 | ], 19 | skipNodeModulesBundle: true, 20 | external: ["cloudflare:workers", "cloudflare:email"], 21 | format: "esm", 22 | sourcemap: true, 23 | fixedExtension: false 24 | }); 25 | 26 | // then run prettier on the generated .d.ts files 27 | execSync("prettier --write ./dist/*.d.ts"); 28 | 29 | process.exit(0); 30 | } 31 | 32 | main().catch((err) => { 33 | // Build failures should fail 34 | console.error(err); 35 | process.exit(1); 36 | }); 37 | -------------------------------------------------------------------------------- /site/ai-playground/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "name": "workers-ai-playground", 4 | "main": "src/server.ts", 5 | "compatibility_date": "2025-10-08", 6 | "compatibility_flags": ["nodejs_compat"], 7 | 8 | "assets": { 9 | "not_found_handling": "single-page-application", 10 | "run_worker_first": ["/api/*", "/agents/*"] 11 | }, 12 | "ai": { 13 | "binding": "AI", 14 | "remote": true 15 | }, 16 | "durable_objects": { 17 | "bindings": [ 18 | { 19 | "class_name": "Playground", 20 | "name": "Playground" 21 | } 22 | ] 23 | }, 24 | "migrations": [ 25 | { 26 | "new_sqlite_classes": ["Playground"], 27 | "tag": "v1" 28 | } 29 | ], 30 | "observability": { 31 | "logs": { 32 | "enabled": true 33 | }, 34 | "traces": { 35 | "enabled": true 36 | } 37 | }, 38 | "vars": { 39 | "HOST": "http://localhost:5173" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | NOTICE 2 | 3 | This project incorporates code and inspiration from the following open source projects: 4 | 5 | 1. Anthropic MCP TS SDK 6 | - License: MIT License 7 | - Repository: https://github.com/modelcontextprotocol/typescript-sdk 8 | - Copyright: Anthropic, PBC 9 | 10 | 2. Coinbase x402 11 | - License: Apache License 2.0 12 | - Repository: https://github.com/coinbase/x402 13 | - Copyright: Coinbase, Inc. 14 | 15 | 3. ethanniser/x402-mcp 16 | - License: MIT License 17 | - Repository: https://github.com/ethanniser/x402-mcp 18 | - Copyright: @ethanniser 19 | 20 | 4. Vercel AI SDK 21 | - License: Apache License 2.0 22 | - Repository: https://github.com/vercel/ai 23 | - Copyright: Vercel, Inc. 24 | 25 | The original licenses and copyright notices from these projects are preserved and should be included with any distribution of this software. 26 | 27 | For a complete list of third-party licenses, see [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md). 28 | -------------------------------------------------------------------------------- /packages/agents/src/serializable.ts: -------------------------------------------------------------------------------- 1 | export type SerializableValue = 2 | | undefined 3 | | null 4 | | string 5 | | number 6 | | boolean 7 | | { [key: string]: SerializableValue } 8 | | SerializableValue[]; 9 | 10 | export type SerializableReturnValue = 11 | | SerializableValue 12 | | void 13 | | Promise 14 | | Promise; 15 | 16 | type AllSerializableValues = A extends [infer First, ...infer Rest] 17 | ? First extends SerializableValue 18 | ? AllSerializableValues 19 | : false 20 | : true; // no params means serializable by default 21 | 22 | // biome-ignore lint: suspicious/noExplicitAny 23 | export type Method = (...args: any[]) => any; 24 | 25 | export type RPCMethod = T extends Method 26 | ? T extends (...arg: infer A) => infer R 27 | ? AllSerializableValues extends true 28 | ? R extends SerializableReturnValue 29 | ? T 30 | : never 31 | : never 32 | : never 33 | : never; 34 | -------------------------------------------------------------------------------- /assets/npm-install-agents.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | $ 19 | npm i agents 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /site/agents/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/client-tools-continuation.md: -------------------------------------------------------------------------------- 1 | # Client Tool Auto-Continuation 2 | 3 | ## Overview 4 | 5 | By default, client-executed tools and server-executed tools behave differently: 6 | 7 | - **Server tools**: Execute and continue responding in the same turn 8 | - **Client tools**: Execute, then require a new request to continue 9 | 10 | The `autoContinueAfterToolResult` option lets client tools behave like server tools - the assistant can call a tool and immediately follow up with a response in one seamless turn. 11 | 12 | ## How It Works 13 | 14 | ```typescript 15 | import { useAgentChat } from "agents/ai-react"; 16 | 17 | const { messages, addToolResult } = useAgentChat({ 18 | agent, 19 | tools: myClientTools, 20 | autoContinueAfterToolResult: true 21 | }); 22 | ``` 23 | 24 | When enabled: 25 | 26 | 1. Client executes the tool and sends the result to the server 27 | 2. Server automatically calls `onChatMessage()` to continue 28 | 3. The LLM's continuation is merged into the same assistant message 29 | 4. User sees a single, seamless response 30 | -------------------------------------------------------------------------------- /examples/codemode/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codemode-demo", 3 | "main": "src/server.ts", 4 | "compatibility_date": "2025-09-25", 5 | "compatibility_flags": [ 6 | "nodejs_compat", 7 | "experimental", 8 | "enable_ctx_exports" 9 | ], 10 | "assets": { 11 | "directory": "public" 12 | }, 13 | "durable_objects": { 14 | "bindings": [ 15 | { 16 | "name": "Codemode", 17 | "class_name": "Codemode" 18 | } 19 | ] 20 | }, 21 | "migrations": [ 22 | { 23 | "tag": "v1", 24 | "new_sqlite_classes": ["Codemode"] 25 | } 26 | ], 27 | "services": [ 28 | { 29 | "binding": "globalOutbound", 30 | "service": "codemode-demo", 31 | "entrypoint": "globalOutbound" 32 | }, 33 | { 34 | "binding": "CodeModeProxy", 35 | "service": "codemode-demo", 36 | "entrypoint": "CodeModeProxy" 37 | } 38 | ], 39 | "observability": { 40 | "enabled": true 41 | }, 42 | "worker_loaders": [ 43 | { 44 | "binding": "LOADER" 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /packages/agents/src/tests/alarms.test.ts: -------------------------------------------------------------------------------- 1 | import { env } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | import type { Env } from "./worker"; 4 | import { getAgentByName } from ".."; 5 | 6 | declare module "cloudflare:test" { 7 | interface ProvidedEnv extends Env {} 8 | } 9 | 10 | describe("scheduled destroys", () => { 11 | it("should not throw when a scheduled callback nukes storage", async () => { 12 | let agentStub = await getAgentByName( 13 | env.TestDestroyScheduleAgent, 14 | "alarm-destroy-repro" 15 | ); 16 | 17 | // Alarm should fire immediately 18 | await agentStub.scheduleSelfDestructingAlarm(); 19 | await expect(agentStub.getStatus()).resolves.toBe("scheduled"); 20 | 21 | // Let the alarm run 22 | await new Promise((resolve) => setTimeout(resolve, 50)); 23 | 24 | agentStub = await getAgentByName( 25 | env.TestDestroyScheduleAgent, 26 | "alarm-destroy-repro" 27 | ); 28 | 29 | await expect(agentStub.getStatus()).resolves.toBe("unscheduled"); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /examples/playground/env.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Generated by Wrangler by running `wrangler types env.d.ts --include-runtime false` (hash: f103d0d6947e92f53f1c4ba8d54acaa6) 3 | declare namespace Cloudflare { 4 | interface GlobalProps { 5 | mainModule: typeof import("./src/server"); 6 | durableNamespaces: "Scheduler" | "Stateful" | "Chat" | "Rpc"; 7 | } 8 | interface Env { 9 | OPENAI_API_KEY: string; 10 | Scheduler: DurableObjectNamespace; 11 | Stateful: DurableObjectNamespace; 12 | Chat: DurableObjectNamespace; 13 | Rpc: DurableObjectNamespace; 14 | ASSETS: Fetcher; 15 | } 16 | } 17 | interface Env extends Cloudflare.Env {} 18 | type StringifyValues> = { 19 | [Binding in keyof EnvType]: EnvType[Binding] extends string 20 | ? EnvType[Binding] 21 | : string; 22 | }; 23 | declare namespace NodeJS { 24 | interface ProcessEnv extends StringifyValues< 25 | Pick 26 | > {} 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/pkg-pr-new.yml: -------------------------------------------------------------------------------- 1 | name: Publish to pkg.pr.new for pre-release 2 | 3 | on: 4 | pull_request: {} 5 | 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 1 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 20.x 16 | cache: "npm" 17 | 18 | - name: Get Playwright version 19 | id: playwright-version 20 | run: echo "version=$(jq -r '.packages["node_modules/playwright"].version' package-lock.json)" >> $GITHUB_OUTPUT 21 | 22 | - name: Cache Playwright browsers 23 | uses: actions/cache@v4 24 | id: playwright-cache 25 | with: 26 | path: ~/.cache/ms-playwright 27 | key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} 28 | 29 | - name: Install dependencies 30 | run: npm ci 31 | 32 | - name: Build packages 33 | run: npm run build 34 | 35 | - name: Publish agents package to pkg.pr.new 36 | run: npx pkg-pr-new publish ./packages/agents 37 | -------------------------------------------------------------------------------- /.github/workflows/pullrequest.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | check: 7 | timeout-minutes: 10 8 | strategy: 9 | matrix: 10 | os: [ 11 | ubuntu-24.04 12 | # windows-latest, 13 | # macos-latest, 14 | ] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 1 20 | 21 | - uses: actions/setup-node@v4 22 | with: 23 | node-version: 20 24 | cache: "npm" 25 | 26 | - name: Get Playwright version 27 | id: playwright-version 28 | run: echo "version=$(jq -r '.packages["node_modules/playwright"].version' package-lock.json)" >> $GITHUB_OUTPUT 29 | 30 | - name: Cache Playwright browsers 31 | uses: actions/cache@v4 32 | id: playwright-cache 33 | with: 34 | path: ~/.cache/ms-playwright 35 | key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} 36 | 37 | - run: npm ci 38 | - run: npm run build 39 | - run: npm run check 40 | - run: CI=true npm run test 41 | -------------------------------------------------------------------------------- /licenses/mit-anthropic-mcp-ts-sdk.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Anthropic, PBC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /licenses/mit-ethanniser-x402-mcp.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) @ethanniser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License Copyright (c) 2025 Cloudflare, Inc. 2 | 3 | Permission is hereby granted, free of 4 | charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, modify, merge, 7 | publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to the 9 | following conditions: 10 | 11 | The above copyright notice and this permission notice 12 | (including the next paragraph) shall be included in all copies or substantial 13 | portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 18 | EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /openai-sdk/pizzaz/README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT Apps 2 | 3 | [Reference](https://developers.openai.com/apps-sdk/build/examples) 4 | 5 | ## Requirements 6 | 7 | You'll need a ChatGPT developer account to be able to use ChatGPT apps (connectors). To do so, from ChatGPT go to **Settings -> Apps & Connectors -> Advanced Settings -> Developer mode ON**. 8 | 9 | ## Usage 10 | 11 | We'll be deploying a PizzaMCP that allows us to render a few different pizza-related components. 12 | All ChatGPT App MCPs are ready-to-ship with `agents`. 13 | 14 | Run `npm run deploy` and make a note of the URL your worker is hosted at. It should be something like `https://pizzaz-mcp..workers.dev`. 15 | 16 | Now, you can go to the ChatGPT interface and add the app as a connector. Simply: 17 | 18 | 1. Go to **Settings -> Apps & Connectors -> Create** 19 | 2. Give it a name and a description (e.g. "Pizzaz" / "Browse and order nearby pizzaz!") 20 | 3. Set the `MCP Server URL` to the Worker URL you just deployed. 21 | 4. This example uses no authentication, so set `No Authentication`. 22 | 5. Carefully read the warning and click `I trust this application`. 23 | 6. Click Create and you're ready to start using your app! 24 | -------------------------------------------------------------------------------- /examples/email-agent/test-mail.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tsx 2 | 3 | // Simple test script for the email agent 4 | async function testEmail() { 5 | const url = "http://localhost:8787/api/test-email"; 6 | 7 | const testData = { 8 | from: "user@example.com", 9 | to: "EmailAgent+test123@example.com", 10 | subject: "Test Email", 11 | body: "Hello from test script!" 12 | }; 13 | 14 | console.log("🧪 Testing email agent with:", testData); 15 | 16 | try { 17 | const response = await fetch(url, { 18 | method: "POST", 19 | headers: { 20 | "Content-Type": "application/json" 21 | }, 22 | body: JSON.stringify(testData) 23 | }); 24 | 25 | if (response.ok) { 26 | const result = await response.json(); 27 | console.log("✅ Success:", result); 28 | } else { 29 | console.error("❌ Error:", response.status, response.statusText); 30 | const errorText = await response.text(); 31 | console.error("Error details:", errorText); 32 | } 33 | } catch (error) { 34 | console.error("❌ Network error:", error); 35 | console.log("💡 Make sure the server is running with: npm run start"); 36 | } 37 | } 38 | 39 | testEmail(); 40 | -------------------------------------------------------------------------------- /openai-sdk/basic/src/server.ts: -------------------------------------------------------------------------------- 1 | import { Agent, run } from "@openai/agents"; 2 | import { Agent as CFAgent, routeAgentRequest } from "agents"; 3 | 4 | // // uncomment to use workers-ai-provider 5 | // import { env } from "cloudflare:workers"; 6 | // import { aisdk } from "@openai/agents-extensions"; 7 | // import { createWorkersAI } from "workers-ai-provider"; 8 | // const model = aisdk( 9 | // createWorkersAI({ binding: env.AI })("@cf/meta/llama-3.2-3b-instruct") 10 | // ); 11 | 12 | export class MyAgent extends CFAgent { 13 | async onRequest() { 14 | const agent = new Agent({ 15 | instructions: "You are a helpful assistant.", 16 | name: "Assistant" 17 | // // uncomment to use workers-ai-provider 18 | // model 19 | }); 20 | 21 | const result = await run( 22 | agent, 23 | "Write a haiku about recursion in programming." 24 | ); 25 | return new Response(result.finalOutput); 26 | } 27 | } 28 | 29 | export default { 30 | async fetch(request: Request, env: Env, _ctx: ExecutionContext) { 31 | return ( 32 | (await routeAgentRequest(request, env)) || 33 | new Response("Not found", { status: 404 }) 34 | ); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /examples/mcp-worker-authenticated/README.md: -------------------------------------------------------------------------------- 1 | # Authenticated MCP Server Example 2 | 3 | This example demonstrates using `createMcpHandler` to create an authenticated MCP server by wrapping it with [`OAuthProvider`](https://github.com/cloudflare/workers-oauth-provider) from `@cloudflare/workers-oauth-provider`. 4 | 5 | This is the simplest way to deploy an authenticated MCP server on Cloudflare Workers. 6 | 7 | ## Setup 8 | 9 | ### 1. Create KV Namespace 10 | 11 | ```bash 12 | wrangler kv namespace create OAUTH_KV 13 | ``` 14 | 15 | ### 2. Update wrangler.jsonc 16 | 17 | ```jsonc 18 | { 19 | "kv_namespaces": [ 20 | { 21 | "binding": "OAUTH_KV", 22 | "id": "your-kv-namespace-id" 23 | } 24 | ] 25 | } 26 | ``` 27 | 28 | ### 3. Deploy 29 | 30 | ```bash 31 | npm run deploy 32 | ``` 33 | 34 | ## How It Works 35 | 36 | 1. **OAuth Provider** handles authentication endpoints 37 | 2. **API Handler** wraps your MCP server with `createMcpHandler` 38 | 3. **OAuth Provider** validates tokens and sets `ctx.props` 39 | 4. **MCP Tools** access user data via `getMcpAuthContext()` 40 | 41 | ``` 42 | Client → OAuth Flow → Token → MCP Request + Bearer Token → ctx.props → getMcpAuthContext() 43 | ``` 44 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.formatOnPaste": false, 5 | "editor.formatOnType": false, 6 | "prettier.requireConfig": true, 7 | "[javascript]": { 8 | "editor.defaultFormatter": "esbenp.prettier-vscode" 9 | }, 10 | "[typescript]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode" 12 | }, 13 | "[javascriptreact]": { 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | }, 16 | "[typescriptreact]": { 17 | "editor.defaultFormatter": "esbenp.prettier-vscode" 18 | }, 19 | "[json]": { 20 | "editor.defaultFormatter": "esbenp.prettier-vscode" 21 | }, 22 | "[jsonc]": { 23 | "editor.defaultFormatter": "esbenp.prettier-vscode" 24 | }, 25 | "[markdown]": { 26 | "editor.defaultFormatter": "esbenp.prettier-vscode" 27 | }, 28 | "[yaml]": { 29 | "editor.defaultFormatter": "esbenp.prettier-vscode" 30 | }, 31 | "[css]": { 32 | "editor.defaultFormatter": "esbenp.prettier-vscode" 33 | }, 34 | "[scss]": { 35 | "editor.defaultFormatter": "esbenp.prettier-vscode" 36 | }, 37 | "[html]": { 38 | "editor.defaultFormatter": "esbenp.prettier-vscode" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/hono-agents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Cloudflare Inc.", 3 | "bugs": { 4 | "url": "https://github.com/cloudflare/agents/issues" 5 | }, 6 | "description": "Add Cloudflare Agents to your Hono app", 7 | "devDependencies": { 8 | "agents": "^0.2.26", 9 | "hono": "^4.10.7" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "exports": { 15 | ".": { 16 | "types": "./dist/index.d.ts", 17 | "import": "./dist/index.js", 18 | "require": "./dist/index.js" 19 | } 20 | }, 21 | "files": [ 22 | "dist", 23 | "README.md" 24 | ], 25 | "keywords": [ 26 | "cloudflare", 27 | "agents", 28 | "hono" 29 | ], 30 | "license": "MIT", 31 | "main": "src/index.ts", 32 | "name": "hono-agents", 33 | "peerDependencies": { 34 | "agents": "^0.2.26", 35 | "hono": "^4.6.17" 36 | }, 37 | "repository": { 38 | "directory": "packages/hono-agents", 39 | "type": "git", 40 | "url": "git+https://github.com/cloudflare/agents.git" 41 | }, 42 | "scripts": { 43 | "build": "tsx ./scripts/build.ts", 44 | "test": "echo \"Error: no test specified\" && exit 1" 45 | }, 46 | "type": "module", 47 | "types": "dist/index.d.ts", 48 | "version": "2.0.7" 49 | } 50 | -------------------------------------------------------------------------------- /examples/playground/src/styles.css: -------------------------------------------------------------------------------- 1 | /* Global styles */ 2 | body { 3 | margin: 0; 4 | font-family: 5 | -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", 6 | Arial, sans-serif; 7 | background-color: #f5f5f5; 8 | } 9 | 10 | /* Global container style */ 11 | .container { 12 | max-width: 800px; 13 | margin: 40px auto; 14 | padding: 0 20px; 15 | } 16 | 17 | /* Global toast notifications */ 18 | .toasts-container { 19 | position: fixed; 20 | top: 20px; 21 | right: 20px; 22 | z-index: 1000; 23 | display: flex; 24 | flex-direction: column; 25 | gap: 10px; 26 | } 27 | 28 | .toast { 29 | min-width: 200px; 30 | padding: 12px 24px; 31 | border-radius: 6px; 32 | color: white; 33 | font-size: 14px; 34 | font-weight: 500; 35 | animation: slideIn 0.3s ease-out forwards; 36 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 37 | } 38 | 39 | .toast-success { 40 | background-color: #28a745; 41 | } 42 | 43 | .toast-error { 44 | background-color: #dc3545; 45 | } 46 | 47 | .toast-info { 48 | background-color: #17a2b8; 49 | } 50 | 51 | @keyframes slideIn { 52 | from { 53 | transform: translateX(100%); 54 | opacity: 0; 55 | } 56 | to { 57 | transform: translateX(0); 58 | opacity: 1; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /docs/observability.md: -------------------------------------------------------------------------------- 1 | # Observability 2 | 3 | `Agent` instances uses the `observability` property to emit various internal events that can be used for logging and monitoring. 4 | 5 | The default behavior is to `console.log()` the event value. 6 | 7 | ``` 8 | { 9 | displayMessage: 'State updated', 10 | id: 'EnOzrS_tEo_8dHy5oyl8q', 11 | payload: {}, 12 | timestamp: 1758005142787, 13 | type: 'state:update' 14 | } 15 | ``` 16 | 17 | This can be configured by overriding the property with an implementation of the `Observability` interface. This interface has a single `emit()` method that takes an `ObservabilityEvent`. 18 | 19 | ```ts 20 | import { Agent } from "agents"; 21 | import { type Observability } from "agents/observability"; 22 | 23 | const observability: Observability = { 24 | emit(event) { 25 | if (event.type === "connect") { 26 | console.log(event.timestamp, event.payload.connectionId); 27 | } 28 | } 29 | }; 30 | 31 | class MyAgent extends Agent { 32 | override observability = observability; 33 | } 34 | ``` 35 | 36 | Or, alternatively, you can set the property to `undefined` to ignore all events. 37 | 38 | ```ts 39 | import { Agent } from "agents"; 40 | 41 | class MyAgent extends Agent { 42 | override observability = undefined; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /packages/agents/src/cli/create.ts: -------------------------------------------------------------------------------- 1 | import yargs from "yargs"; 2 | import { hideBin } from "yargs/helpers"; 3 | 4 | export function createCli(argv = process.argv) { 5 | return yargs(hideBin(argv)) 6 | .scriptName("agents") 7 | .usage("$0 [options]") 8 | .command( 9 | ["init", "create"], 10 | "Initialize an agents project", 11 | (cmd) => cmd, 12 | async () => { 13 | console.log("agents init: not implemented yet"); 14 | process.exit(0); 15 | } 16 | ) 17 | .command( 18 | "dev", 19 | "Start development server", 20 | (cmd) => cmd, 21 | async () => { 22 | console.log("agents dev: not implemented yet"); 23 | process.exit(0); 24 | } 25 | ) 26 | .command( 27 | "deploy", 28 | "Deploy agents to Cloudflare", 29 | (cmd) => cmd, 30 | async () => { 31 | console.log("agents deploy: not implemented yet"); 32 | process.exit(0); 33 | } 34 | ) 35 | .command( 36 | "mcp", 37 | "The agents mcp server", 38 | (cmd) => cmd, 39 | async () => { 40 | console.log("agents mcp: not implemented yet"); 41 | process.exit(0); 42 | } 43 | ) 44 | .demandCommand(1, "Please provide a command") 45 | .strict() 46 | .help(); 47 | } 48 | -------------------------------------------------------------------------------- /examples/mcp/README.md: -------------------------------------------------------------------------------- 1 | # McpAgent demo 2 | 3 | A minimal example showing an `McpAgent` running in Wrangler, being accessed from the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). 4 | 5 | ## Instruction 6 | 7 | ```sh 8 | npm install 9 | npm start 10 | ``` 11 | 12 | This will start an MCP server on `http://localhost:5174/mcp` and open the MCP inspector in your browser. 13 | 14 | Set your **Transport Type** to **Streamable HTTP** and your **URL** to `http://localhost:5174/mcp`, then click **Connect**. You should see the following: 15 | 16 | ![Image](https://github.com/user-attachments/assets/ef31b754-755d-4022-9549-382854a19f77) 17 | 18 | Inside your `McpAgent`'s `init()` method, you can define resources, tools, etc: 19 | 20 | ```ts 21 | export class MyMCP extends McpAgent { 22 | server = new McpServer({ 23 | name: "Demo", 24 | version: "1.0.0" 25 | }); 26 | 27 | async init() { 28 | this.server.resource("counter", "mcp://resource/counter", (uri) => { 29 | // ... 30 | }); 31 | 32 | this.server.registerTool( 33 | "add", 34 | { 35 | description: "Add to the counter, stored in the MCP", 36 | inputSchema: { a: z.number() } 37 | }, 38 | async ({ a }) => { 39 | // add your logic here 40 | } 41 | ); 42 | } 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/wrangler.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/wrangler/config-schema.json", 3 | "account_id": "85d0c02b57ed75faf9b18f92d5c01602", 4 | 5 | "assets": { 6 | "directory": "public" 7 | }, 8 | "compatibility_date": "2025-01-29", 9 | "compatibility_flags": ["nodejs_compat"], 10 | 11 | "durable_objects": { 12 | "bindings": [ 13 | { 14 | "class_name": "Sequential", 15 | "name": "sequential" 16 | }, 17 | { 18 | "class_name": "Routing", 19 | "name": "routing" 20 | }, 21 | { 22 | "class_name": "Parallel", 23 | "name": "parallel" 24 | }, 25 | { 26 | "class_name": "Orchestrator", 27 | "name": "orchestrator" 28 | }, 29 | { 30 | "class_name": "Evaluator", 31 | "name": "evaluator" 32 | } 33 | ] 34 | }, 35 | "main": "src/server.tsx", 36 | 37 | "migrations": [ 38 | { 39 | "new_sqlite_classes": [ 40 | "Sequential", 41 | "Routing", 42 | "Parallel", 43 | "Orchestrator", 44 | "Evaluator" 45 | ], 46 | "tag": "v1" 47 | } 48 | ], 49 | "name": "anthropic-agent-patterns", 50 | 51 | "vars": { 52 | "AI_GATEWAY_ACCOUNT_ID": "85d0c02b57ed75faf9b18f92d5c01602", 53 | "AI_GATEWAY_ID": "anthropic-agent-patterns" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/agents/src/core/events.ts: -------------------------------------------------------------------------------- 1 | export interface Disposable { 2 | dispose(): void; 3 | } 4 | 5 | export function toDisposable(fn: () => void): Disposable { 6 | return { dispose: fn }; 7 | } 8 | 9 | export class DisposableStore implements Disposable { 10 | private readonly _items: Disposable[] = []; 11 | 12 | add(d: T): T { 13 | this._items.push(d); 14 | return d; 15 | } 16 | 17 | dispose(): void { 18 | while (this._items.length) { 19 | try { 20 | this._items.pop()!.dispose(); 21 | } catch { 22 | // best-effort cleanup 23 | } 24 | } 25 | } 26 | } 27 | 28 | export type Event = (listener: (e: T) => void) => Disposable; 29 | 30 | export class Emitter implements Disposable { 31 | private _listeners: Set<(e: T) => void> = new Set(); 32 | 33 | readonly event: Event = (listener) => { 34 | this._listeners.add(listener); 35 | return toDisposable(() => this._listeners.delete(listener)); 36 | }; 37 | 38 | fire(data: T): void { 39 | for (const listener of [...this._listeners]) { 40 | try { 41 | listener(data); 42 | } catch (err) { 43 | // do not let one bad listener break others 44 | console.error("Emitter listener error:", err); 45 | } 46 | } 47 | } 48 | 49 | dispose(): void { 50 | this._listeners.clear(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /site/ai-playground/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 5 | plugins: [], 6 | theme: { 7 | extend: { 8 | animation: { 9 | "gradient-background": "gradient-background 3s linear infinite" 10 | }, 11 | backgroundImage: { 12 | ai: "linear-gradient(75deg, #901475, #CE2F55, #FF6633)", 13 | "ai-loop": 14 | "linear-gradient(75deg, #901475, #CE2F55, #FF6633, #CE2F55, #901475)" 15 | }, 16 | keyframes: { 17 | "gradient-background": { 18 | "0%": { backgroundPosition: "0% 0%" }, 19 | "100%": { backgroundPosition: "200% 0%" } 20 | } 21 | } 22 | }, 23 | fontFamily: { 24 | mono: [ 25 | "ui-monospace", 26 | "SFMono-Regular", 27 | "Menlo", 28 | "Monaco", 29 | "Consolas", 30 | "Liberation Mono", 31 | "Courier New", 32 | "monospace" 33 | ], 34 | system: [ 35 | "-apple-system", 36 | "BlinkMacSystemFont", 37 | "Segoe UI", 38 | "Roboto", 39 | "Oxygen", 40 | "Ubuntu", 41 | "Cantarell", 42 | "Fira Sans", 43 | "Droid Sans", 44 | "Helvetica Neue", 45 | "sans-serif" 46 | ] 47 | } 48 | } 49 | } satisfies Config; 50 | -------------------------------------------------------------------------------- /site/agents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/agents-site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "wrangler dev", 8 | "build": "astro build", 9 | "types": "wrangler types env.d.ts --include-runtime false", 10 | "deploy": "npm run build && wrangler deploy" 11 | }, 12 | "dependencies": { 13 | "@astrojs/cloudflare": "^12.6.12", 14 | "@astrojs/react": "^4.4.2", 15 | "@cfworker/json-schema": "^4.1.1", 16 | "@chonkiejs/core": "^0.0.5", 17 | "@gsap/react": "^2.1.2", 18 | "@orama/orama": "^3.1.16", 19 | "@use-it/interval": "^1.0.0", 20 | "astro": "^5.16.1", 21 | "clsx": "^2.1.1", 22 | "effect": "^3.19.7", 23 | "framer-motion": "^12.23.24", 24 | "gsap": "^3.13.0", 25 | "react": "^19.2.0", 26 | "react-dom": "^19.2.0", 27 | "react-wrap-balancer": "^1.1.1", 28 | "shiki": "^3.17.0", 29 | "tailwindcss": "^4.1.17" 30 | }, 31 | "devDependencies": { 32 | "@tailwindcss/postcss": "^4", 33 | "@tailwindcss/vite": "^4", 34 | "@types/node": "^24.10.1", 35 | "@types/react": "^19.2.7", 36 | "@types/react-dom": "^19.2.3", 37 | "typescript": "^5.9.3", 38 | "wrangler": "^4.51.0" 39 | }, 40 | "optionalDependencies": { 41 | "lightningcss-darwin-arm64": "1.30.2", 42 | "lightningcss-linux-x64-gnu": "1.30.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /site/agents/src/components/_components/chat-bubble.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import type { CSSProperties, ReactNode } from "react"; 3 | 4 | export function ChatBubble({ 5 | children, 6 | arrowPosition = "left", 7 | style 8 | }: { 9 | children: ReactNode; 10 | arrowPosition?: "left" | "right"; 11 | style?: CSSProperties; 12 | }) { 13 | return ( 14 |
15 |
16 | {children} 17 |
18 | 19 |
20 | ); 21 | } 22 | 23 | export function ChatArrow({ 24 | position = "left" 25 | }: { 26 | position?: "left" | "right"; 27 | }) { 28 | return ( 29 | 39 | 45 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /openai-sdk/handoffs/src/server.ts: -------------------------------------------------------------------------------- 1 | import { Agent, run } from "@openai/agents"; 2 | import { Agent as CFAgent, routeAgentRequest } from "agents"; 3 | 4 | type Env = { 5 | MyAgent: DurableObjectNamespace; 6 | }; 7 | 8 | export class MyAgent extends CFAgent { 9 | async onRequest() { 10 | const historyTutorAgent = new Agent({ 11 | instructions: 12 | "You provide assistance with historical queries. Explain important events and context clearly.", 13 | name: "History Tutor" 14 | }); 15 | 16 | const mathTutorAgent = new Agent({ 17 | instructions: 18 | "You provide help with math problems. Explain your reasoning at each step and include examples", 19 | name: "Math Tutor" 20 | }); 21 | 22 | const triageAgent = new Agent({ 23 | handoffs: [historyTutorAgent, mathTutorAgent], 24 | instructions: 25 | "You determine which agent to use based on the user's homework question", 26 | name: "Triage Agent" 27 | }); 28 | 29 | const result = await run(triageAgent, "What is the capital of France?"); 30 | console.log(JSON.stringify(result, null, 2)); 31 | return Response.json(result.finalOutput); 32 | } 33 | } 34 | 35 | export default { 36 | async fetch(request: Request, env: Env, _ctx: ExecutionContext) { 37 | return ( 38 | (await routeAgentRequest(request, env)) || 39 | new Response("Not found", { status: 404 }) 40 | ); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /site/agents/src/components/logo.tsx: -------------------------------------------------------------------------------- 1 | export function Logo({ size = 60 }: { size?: number | string }) { 2 | return ( 3 | 9 | 10 | 15 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/agents/src/observability/index.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentAgent } from "../index"; 2 | import type { AgentObservabilityEvent } from "./agent"; 3 | import type { MCPObservabilityEvent } from "./mcp"; 4 | 5 | /** 6 | * Union of all observability event types from different domains 7 | */ 8 | export type ObservabilityEvent = 9 | | AgentObservabilityEvent 10 | | MCPObservabilityEvent; 11 | 12 | export interface Observability { 13 | /** 14 | * Emit an event for the Agent's observability implementation to handle. 15 | * @param event - The event to emit 16 | * @param ctx - The execution context of the invocation (optional) 17 | */ 18 | emit(event: ObservabilityEvent, ctx?: DurableObjectState): void; 19 | } 20 | 21 | /** 22 | * A generic observability implementation that logs events to the console. 23 | */ 24 | export const genericObservability: Observability = { 25 | emit(event) { 26 | // In local mode, we display a pretty-print version of the event for easier debugging. 27 | if (isLocalMode()) { 28 | console.log(event.displayMessage); 29 | return; 30 | } 31 | 32 | console.log(event); 33 | } 34 | }; 35 | 36 | let localMode = false; 37 | 38 | function isLocalMode() { 39 | if (localMode) { 40 | return true; 41 | } 42 | const { request } = getCurrentAgent(); 43 | if (!request) { 44 | return false; 45 | } 46 | 47 | const url = new URL(request.url); 48 | localMode = url.hostname === "localhost"; 49 | return localMode; 50 | } 51 | -------------------------------------------------------------------------------- /packages/agents/src/tests-d/example-stub.test-d.ts: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/correctness/useHookAtTopLevel: testing types */ 2 | import type { env } from "cloudflare:workers"; 3 | import { Agent, callable } from ".."; 4 | import { useAgent } from "../react.tsx"; 5 | 6 | class MyAgent extends Agent { 7 | @callable() 8 | sayHello(name?: string): string { 9 | return `Hello, ${name ?? "World"}!`; 10 | } 11 | 12 | @callable() 13 | async perform(_task: string, _p1?: number): Promise { 14 | // do something 15 | } 16 | 17 | // not decorated with @callable() 18 | nonRpc(): void { 19 | // do something 20 | } 21 | } 22 | 23 | const { stub } = useAgent({ agent: "my-agent" }); 24 | // return type is promisified 25 | stub.sayHello() satisfies Promise; 26 | 27 | // @ts-expect-error first argument is not a string 28 | await stub.sayHello(1); 29 | 30 | await stub.perform("some task", 1); 31 | await stub.perform("another task"); 32 | // @ts-expect-error requires parameters 33 | await stub.perform(); 34 | 35 | // we cannot exclude it because typescript doesn't have a way 36 | // to exclude based on decorators 37 | await stub.nonRpc(); 38 | 39 | // @ts-expect-error nonSerializable is not serializable 40 | await stub.nonSerializable("hello", new Date()); 41 | 42 | const { stub: stub2 } = useAgent, {}>({ 43 | agent: "my-agent" 44 | }); 45 | stub2.sayHello(); 46 | // @ts-expect-error nonRpc excluded from useAgent 47 | stub2.nonRpc(); 48 | -------------------------------------------------------------------------------- /scripts/typecheck.ts: -------------------------------------------------------------------------------- 1 | import { type ExecException, execSync } from "node:child_process"; 2 | import fg from "fast-glob"; 3 | 4 | const tsconfigs: string[] = []; 5 | 6 | for await (const file of await fg.glob("**/tsconfig.json")) { 7 | if (file.includes("node_modules")) continue; 8 | tsconfigs.push(file); 9 | } 10 | 11 | console.log(`Typechecking ${tsconfigs.length} projects...`); 12 | 13 | type Result = { 14 | tsconfig: string; 15 | success: boolean; 16 | output: string; 17 | }; 18 | 19 | const results: Result[] = []; 20 | 21 | for (const tsconfig of tsconfigs) { 22 | console.log(`Checking ${tsconfig}...`); 23 | try { 24 | const output = execSync(`tsc -p ${tsconfig}`, { 25 | encoding: "utf-8", 26 | stdio: ["pipe", "pipe", "pipe"] 27 | }); 28 | results.push({ tsconfig, success: true, output }); 29 | console.log(`✅ ${tsconfig} - OK`); 30 | } catch (rawError: unknown) { 31 | const error = rawError as ExecException; 32 | 33 | const output = 34 | error.stdout?.toString() || `${error.stderr?.toString()}` || ""; 35 | results.push({ tsconfig, success: false, output }); 36 | console.error(`❌ ${tsconfig} - Failed:`); 37 | console.error(output); 38 | } 39 | } 40 | 41 | const failed = results.filter((r) => !r.success); 42 | 43 | if (failed.length > 0) { 44 | console.error( 45 | `\n${failed.length} of ${tsconfigs.length} projects failed to typecheck!` 46 | ); 47 | process.exit(1); 48 | } 49 | 50 | console.log("All projects typecheck successfully!"); 51 | -------------------------------------------------------------------------------- /packages/agents/src/tests-d/example.test-d.ts: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/correctness/useHookAtTopLevel: testing types */ 2 | import type { env } from "cloudflare:workers"; 3 | import { Agent, callable } from ".."; 4 | import { useAgent } from "../react.tsx"; 5 | 6 | class MyAgent extends Agent { 7 | @callable() 8 | sayHello(name?: string): string { 9 | return `Hello, ${name ?? "World"}!`; 10 | } 11 | 12 | @callable() 13 | async perform(_task: string, _p1?: number): Promise { 14 | // do something 15 | } 16 | 17 | // not decorated with @callable() 18 | nonRpc(): void { 19 | // do something 20 | } 21 | } 22 | 23 | const agent = useAgent({ agent: "my-agent" }); 24 | // return type is promisified 25 | agent.call("sayHello") satisfies Promise; 26 | 27 | // @ts-expect-error first argument is not a string 28 | await agent.call("sayHello", [1]); 29 | 30 | await agent.call("perform", ["some task", 1]); 31 | await agent.call("perform", ["another task"]); 32 | // @ts-expect-error requires parameters 33 | await agent.call("perform"); 34 | 35 | // we cannot exclude it because typescript doesn't have a way 36 | // to exclude based on decorators 37 | await agent.call("nonRpc"); 38 | 39 | // @ts-expect-error nonSerializable is not serializable 40 | await agent.call("nonSerializable", ["hello", new Date()]); 41 | 42 | const agent2 = useAgent, {}>({ agent: "my-agent" }); 43 | agent2.call("sayHello"); 44 | // @ts-expect-error nonRpc excluded from useAgent 45 | agent2.call("nonRpc"); 46 | -------------------------------------------------------------------------------- /examples/mcp-client/README.md: -------------------------------------------------------------------------------- 1 | # MCP Client Demo Using Agents 2 | 3 | A minimal example showing an `Agent` as an MCP client with support for both SSE and HTTP Streamable transports. 4 | 5 | ## Transport Options 6 | 7 | The MCP client supports two transport types: 8 | 9 | - **HTTP Streamable** (recommended): Uses HTTP POST + SSE for better performance and reliability 10 | - **SSE (Server-Sent Events)** 11 | 12 | ## Instructions 13 | 14 | First, start an MCP server. A simple example can be found in `examples/mcp`, which already has a valid binding setup. 15 | 16 | Then, follow the steps below to setup the client: 17 | 18 | 1. This example uses a pre-built version of the agents package. Run `npm run build` in the root of this repo to build it. 19 | 2. Copy the `.dev.vars.example` file in this directory to a new file called `.dev.vars`. 20 | 3. Run `npm install` from this directory. 21 | 4. Run `npm start` from this directory. 22 | 23 | Tap "O + enter" to open the front end. It should list out all the tools, prompts, and resources available for each server added. 24 | 25 | ## Usage 26 | 27 | The recommended way to add MCP servers is via `Agent.addMcpServer()`: 28 | 29 | ```typescript 30 | export class MyAgent extends Agent { 31 | async addServer(name: string, url: string, callbackHost: string) { 32 | // Uses HTTP Streamable transport by default 33 | await this.addMcpServer(name, url, callbackHost); 34 | } 35 | } 36 | ``` 37 | 38 | The MCP client handles OAuth authentication automatically using the built-in `DurableObjectOAuthClientProvider`. 39 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/flows/02 routing.txt: -------------------------------------------------------------------------------- 1 | import { openai } from '@ai-sdk/openai'; 2 | import { generateObject, generateText } from 'ai'; 3 | import { z } from 'zod'; 4 | 5 | async function handleCustomerQuery(query: string) { 6 | const model = openai('gpt-4o'); 7 | 8 | // First step: Classify the query type 9 | const { object: classification } = await generateObject({ 10 | model, 11 | schema: z.object({ 12 | reasoning: z.string(), 13 | type: z.enum(['general', 'refund', 'technical']), 14 | complexity: z.enum(['simple', 'complex']), 15 | }), 16 | prompt: `Classify this customer query: 17 | ${query} 18 | 19 | Determine: 20 | 1. Query type (general, refund, or technical) 21 | 2. Complexity (simple or complex) 22 | 3. Brief reasoning for classification`, 23 | }); 24 | 25 | // Route based on classification 26 | // Set model and system prompt based on query type and complexity 27 | const { text: response } = await generateText({ 28 | model: 29 | classification.complexity === 'simple' 30 | ? openai('gpt-4o-mini') 31 | : openai('o1-mini'), 32 | system: { 33 | general: 34 | 'You are an expert customer service agent handling general inquiries.', 35 | refund: 36 | 'You are a customer service agent specializing in refund requests. Follow company policy and collect necessary information.', 37 | technical: 38 | 'You are a technical support specialist with deep product knowledge. Focus on clear step-by-step troubleshooting.', 39 | }[classification.type], 40 | prompt: query, 41 | }); 42 | 43 | return { response, classification }; 44 | } -------------------------------------------------------------------------------- /site/ai-playground/src/components/ModelRow.tsx: -------------------------------------------------------------------------------- 1 | import type { Model } from "../models"; 2 | 3 | const ModelRow = ({ model }: { model: Model }) => { 4 | const [_provider, _author, name] = model.name.split("/"); 5 | const tags: string[] = model.properties 6 | .map( 7 | ({ 8 | property_id, 9 | value 10 | }: { 11 | property_id: string; 12 | value: string; 13 | }): string | null => { 14 | if (property_id === "beta" && value === "true") { 15 | return "Beta"; 16 | } 17 | 18 | if (property_id === "lora" && value === "true") { 19 | return "LoRA"; 20 | } 21 | 22 | if (property_id === "function_calling" && value === "true") { 23 | return "MCP"; 24 | } 25 | 26 | return null; 27 | } 28 | ) 29 | .filter((val): val is string => val !== null); 30 | 31 | // TODO: Update label for LoRA 32 | return ( 33 |
37 | {name} 38 |
39 | {tags.map((tag: string) => ( 40 | 50 | {tag} 51 | 52 | ))} 53 |
54 |
55 | ); 56 | }; 57 | 58 | export default ModelRow; 59 | -------------------------------------------------------------------------------- /examples/resumable-stream-chat/src/server.ts: -------------------------------------------------------------------------------- 1 | import { openai } from "@ai-sdk/openai"; 2 | import { type AgentNamespace, routeAgentRequest } from "agents"; 3 | import { AIChatAgent } from "agents/ai-chat-agent"; 4 | import { 5 | streamText, 6 | convertToModelMessages, 7 | createUIMessageStream, 8 | createUIMessageStreamResponse 9 | } from "ai"; 10 | 11 | type Env = { 12 | OPENAI_API_KEY: string; 13 | ResumableStreamingChat: AgentNamespace; 14 | }; 15 | 16 | /** 17 | * Resumable Streaming Chat Agent 18 | * 19 | * This example demonstrates automatic resumable streaming built into AIChatAgent. 20 | * When a client disconnects and reconnects during streaming: 21 | * 1. The server automatically detects the active stream 22 | * 2. Sends CF_AGENT_STREAM_RESUMING notification 23 | * 3. Client ACKs and receives all buffered chunks 24 | * 25 | * No special setup required - just use onChatMessage() as usual. 26 | */ 27 | export class ResumableStreamingChat extends AIChatAgent { 28 | /** 29 | * Handle incoming chat messages. 30 | */ 31 | async onChatMessage() { 32 | const stream = createUIMessageStream({ 33 | execute: async ({ writer }) => { 34 | const result = streamText({ 35 | model: openai("gpt-4o"), 36 | messages: convertToModelMessages(this.messages) 37 | }); 38 | 39 | writer.merge(result.toUIMessageStream()); 40 | } 41 | }); 42 | return createUIMessageStreamResponse({ stream }); 43 | } 44 | } 45 | 46 | export default { 47 | async fetch(request: Request, env: Env) { 48 | return ( 49 | (await routeAgentRequest(request, env)) || 50 | new Response("Not found", { status: 404 }) 51 | ); 52 | } 53 | } satisfies ExportedHandler; 54 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/flows/01 sequential.txt: -------------------------------------------------------------------------------- 1 | import { openai } from "@ai-sdk/openai"; 2 | import { generateText, generateObject } from "ai"; 3 | import { z } from "zod"; 4 | 5 | export default async function generateMarketingCopy(input: string) { 6 | const model = openai("gpt-4o"); 7 | 8 | // First step: Generate marketing copy 9 | const { text: copy } = await generateText({ 10 | model, 11 | prompt: `Write persuasive marketing copy for: ${input}. Focus on benefits and emotional appeal.`, 12 | }); 13 | 14 | // Perform quality check on copy 15 | const { object: qualityMetrics } = await generateObject({ 16 | model, 17 | schema: z.object({ 18 | hasCallToAction: z.boolean(), 19 | emotionalAppeal: z.number().min(1).max(10), 20 | clarity: z.number().min(1).max(10), 21 | }), 22 | prompt: `Evaluate this marketing copy for: 23 | 1. Presence of call to action (true/false) 24 | 2. Emotional appeal (1-10) 25 | 3. Clarity (1-10) 26 | 27 | Copy to evaluate: ${copy}`, 28 | }); 29 | 30 | // If quality check fails, regenerate with more specific instructions 31 | if ( 32 | !qualityMetrics.hasCallToAction || 33 | qualityMetrics.emotionalAppeal < 7 || 34 | qualityMetrics.clarity < 7 35 | ) { 36 | const { text: improvedCopy } = await generateText({ 37 | model, 38 | prompt: `Rewrite this marketing copy with: 39 | ${!qualityMetrics.hasCallToAction ? "- A clear call to action" : ""} 40 | ${qualityMetrics.emotionalAppeal < 7 ? "- Stronger emotional appeal" : ""} 41 | ${qualityMetrics.clarity < 7 ? "- Improved clarity and directness" : ""} 42 | 43 | Original copy: ${copy}`, 44 | }); 45 | return { copy: improvedCopy, qualityMetrics }; 46 | } 47 | 48 | return { copy, qualityMetrics }; 49 | } 50 | -------------------------------------------------------------------------------- /.github/resolve-workspace-versions.ts: -------------------------------------------------------------------------------- 1 | // this looks for all package.jsons in /packages/**/package.json 2 | // and replaces it with the actual version ids 3 | 4 | import * as fs from "node:fs"; 5 | import fg from "fast-glob"; 6 | 7 | // we do this in 2 passes 8 | // first let's cycle through all packages and get thier version numbers 9 | 10 | // biome-ignore lint/suspicious/noExplicitAny: vibes 11 | const packageJsons: Record = {}; 12 | 13 | for await (const file of await fg.glob( 14 | "./(packages|examples|guides)/*/package.json" 15 | )) { 16 | const packageJson = JSON.parse(fs.readFileSync(file, "utf8")); 17 | packageJsons[packageJson.name] = { 18 | file, 19 | packageJson 20 | }; 21 | } 22 | 23 | // then we'll revisit them, and replace any "workspace:*" references 24 | // with "^(actual version)" 25 | 26 | for (const [packageName, { file, packageJson }] of Object.entries( 27 | packageJsons 28 | )) { 29 | let changed = false; 30 | for (const field of [ 31 | "dependencies", 32 | "devDependencies", 33 | "peerDependencies", 34 | "optionalDependencies" 35 | ]) { 36 | for (const [dependencyName, dependencyVersion] of Object.entries( 37 | packageJson[field] || {} 38 | )) { 39 | if (dependencyName in packageJsons) { 40 | let actualVersion = packageJsons[dependencyName].packageJson.version; 41 | if (!actualVersion.startsWith("0.0.0-")) { 42 | actualVersion = `^${actualVersion}`; 43 | } 44 | 45 | console.log( 46 | `${packageName}: setting ${field}.${dependencyName} to ${actualVersion}` 47 | ); 48 | packageJson[field][dependencyName] = actualVersion; 49 | changed = true; 50 | } 51 | } 52 | } 53 | if (changed) { 54 | fs.writeFileSync(file, `${JSON.stringify(packageJson, null, 2)}\n`); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/agents/src/tests-d/use-agent-stub.test-d.ts: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/correctness/useHookAtTopLevel: testing types */ 2 | import type { env } from "cloudflare:workers"; 3 | import { Agent } from ".."; 4 | import { useAgent } from "../react"; 5 | 6 | declare class A extends Agent { 7 | prop: string; 8 | f1: () => number; 9 | f2: (a: string) => void; 10 | f3: (a: number, b: string) => Promise; 11 | f4: (a?: string) => void; 12 | f5: (a: string | undefined) => void; 13 | f6: () => Promise; 14 | nonSerializableParams: (a: string, b: { c: Date }) => void; 15 | nonSerializableReturn: (a: string) => Date; 16 | } 17 | 18 | const { stub } = useAgent({ 19 | agent: "test" 20 | }); 21 | 22 | stub.f1() satisfies Promise; 23 | // @ts-expect-error 24 | stub.f1(1) satisfies Promise; 25 | 26 | stub.f2("test") satisfies Promise; 27 | // @ts-expect-error should receive a [string] 28 | stub.f2(); 29 | // @ts-expect-error 30 | stub.f2(1); 31 | 32 | stub.f3(1, "test") satisfies Promise; 33 | // @ts-expect-error should receive a [number, string] 34 | stub.f3() satisfies Promise; 35 | // @ts-expect-error 36 | stub.f3(1) satisfies Promise; 37 | 38 | stub.f4() satisfies Promise; 39 | stub.f4() satisfies Promise; 40 | stub.f4(undefined) satisfies Promise; 41 | 42 | // @ts-expect-error should receive a [string | undefined] 43 | stub.f5() satisfies Promise; 44 | stub.f5(undefined) satisfies Promise; 45 | 46 | stub.f6() satisfies Promise; 47 | 48 | // @ts-expect-error should not have base Agent methods 49 | stub.setState({ prop: "test" }); 50 | 51 | // @ts-expect-error Date parameter not serializable 52 | stub.nonSerializableParams("test", { c: new Date() }); 53 | // @ts-expect-error Date return not serializable 54 | stub.nonSerializableReturn("test"); 55 | -------------------------------------------------------------------------------- /packages/agents/src/e2e/remote-mcp-server/mcp.ts: -------------------------------------------------------------------------------- 1 | import { McpAgent } from "../../mcp"; 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 3 | import { z } from "zod"; 4 | 5 | export type AuthProps = { email?: string }; 6 | 7 | type Env = unknown; 8 | 9 | type State = {}; 10 | 11 | export class WhoamiMCP extends McpAgent { 12 | server = new McpServer({ name: "whoami-mcp", version: "0.1.0" }); 13 | 14 | async init() { 15 | // Proves we kept the email from the execution context 16 | const email = this.props?.email; 17 | this.server.registerTool( 18 | "whoami", 19 | { 20 | description: "Return the authenticated email (from auth props)" 21 | }, 22 | async () => { 23 | return { 24 | content: [{ type: "text" as const, text: email ?? "unknown" }] 25 | }; 26 | } 27 | ); 28 | } 29 | } 30 | 31 | export class AddMCP extends McpAgent< 32 | Env, 33 | State, 34 | AuthProps & { echoAvailable: boolean } 35 | > { 36 | server = new McpServer({ name: "add-mcp", version: "0.1.0" }); 37 | 38 | async init() { 39 | // Simple echo tool that's gated behind a feature flag 40 | if (this.props?.echoAvailable) { 41 | this.server.registerTool( 42 | "echo", 43 | { 44 | description: "Echo a message", 45 | inputSchema: { msg: z.string() } 46 | }, 47 | async ({ msg }) => { 48 | return { 49 | content: [{ type: "text", text: msg }] 50 | }; 51 | } 52 | ); 53 | } 54 | 55 | // Simple math tool 56 | this.server.registerTool( 57 | "add", 58 | { 59 | description: "Add two numbers", 60 | inputSchema: { a: z.number(), b: z.number() } 61 | }, 62 | async ({ a, b }) => { 63 | return { 64 | content: [{ type: "text", text: String(a + b) }] 65 | }; 66 | } 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /site/ai-playground/src/components/ReasoningCard.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | interface ReasoningCardProps { 4 | part: { 5 | type: "reasoning"; 6 | text: string; 7 | state?: "streaming" | "done"; 8 | }; 9 | } 10 | 11 | export const ReasoningCard = ({ part }: ReasoningCardProps) => { 12 | const [isExpanded, setIsExpanded] = useState(true); 13 | 14 | return ( 15 |
16 | 46 | 47 |
52 |
53 |           {part.text}
54 |         
55 |
56 |
57 | ); 58 | }; 59 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/2.3.7/schema.json", 3 | "assist": { 4 | "actions": { 5 | "source": { 6 | "useSortedKeys": "off", 7 | "organizeImports": "off" 8 | } 9 | }, 10 | "enabled": true 11 | }, 12 | "files": { 13 | "ignoreUnknown": false, 14 | "includes": [ 15 | "examples/**", 16 | "openai-sdk/**", 17 | "packages/**", 18 | "guides/**", 19 | "!node_modules", 20 | "!**/node_modules", 21 | "!dist", 22 | "!**/dist", 23 | "!.wrangler", 24 | "!**/.wrangler", 25 | "!wrangler.jsonc", 26 | "!**/wrangler.jsonc", 27 | "!./tsconfig.base.json", 28 | "!**/tsconfig.base.json", 29 | "!**/normalize.css", 30 | "!package.json", 31 | "!**/package.json", 32 | "!package-lock.json" 33 | ] 34 | }, 35 | "formatter": { 36 | "enabled": false, 37 | "indentStyle": "tab" 38 | }, 39 | "linter": { 40 | "enabled": true, 41 | "rules": { 42 | "a11y": { 43 | "useKeyWithClickEvents": "off" 44 | }, 45 | "complexity": { 46 | "noBannedTypes": "off", 47 | "noImportantStyles": "off" 48 | }, 49 | "suspicious": { 50 | "noExplicitAny": "error", 51 | "noEmptyInterface": "off" 52 | }, 53 | "recommended": true, 54 | "style": { 55 | "noInferrableTypes": "error", 56 | "noNonNullAssertion": "off", 57 | "noParameterAssign": "error", 58 | "noUnusedTemplateLiteral": "error", 59 | "noUselessElse": "off", 60 | "useAsConstAssertion": "error", 61 | "useDefaultParameterLast": "error", 62 | "useEnumInitializers": "error", 63 | "useNumberNamespace": "error", 64 | "useSelfClosingElements": "error", 65 | "useSingleVarDeclarator": "error" 66 | } 67 | } 68 | }, 69 | "vcs": { 70 | "clientKind": "git", 71 | "enabled": false, 72 | "useIgnoreFile": false 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/agents/src/tests/wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "compatibility_date": "2025-04-17", 3 | "compatibility_flags": [ 4 | "nodejs_compat", 5 | // adding these flags since the vitest runner needs them 6 | "enable_nodejs_tty_module", 7 | "enable_nodejs_fs_module", 8 | "enable_nodejs_http_modules", 9 | "enable_nodejs_perf_hooks_module" 10 | ], 11 | "durable_objects": { 12 | "bindings": [ 13 | { 14 | "class_name": "TestMcpAgent", 15 | "name": "MCP_OBJECT" 16 | }, 17 | { 18 | "class_name": "TestEmailAgent", 19 | "name": "EmailAgent" 20 | }, 21 | { 22 | "class_name": "TestCaseSensitiveAgent", 23 | "name": "CaseSensitiveAgent" 24 | }, 25 | { 26 | "class_name": "TestUserNotificationAgent", 27 | "name": "UserNotificationAgent" 28 | }, 29 | { "class_name": "TestRaceAgent", "name": "TAG_AGENT" }, 30 | { 31 | "class_name": "TestChatAgent", 32 | "name": "TestChatAgent" 33 | }, 34 | { 35 | "class_name": "TestOAuthAgent", 36 | "name": "TestOAuthAgent" 37 | }, 38 | { 39 | "class_name": "TestMcpJurisdiction", 40 | "name": "TEST_MCP_JURISDICTION" 41 | }, 42 | { 43 | "class_name": "TestDestroyScheduleAgent", 44 | "name": "TestDestroyScheduleAgent" 45 | }, 46 | { 47 | "class_name": "TestScheduleAgent", 48 | "name": "TestScheduleAgent" 49 | } 50 | ] 51 | }, 52 | "main": "worker.ts", 53 | "migrations": [ 54 | { 55 | "new_sqlite_classes": [ 56 | "TestMcpAgent", 57 | "TestEmailAgent", 58 | "TestCaseSensitiveAgent", 59 | "TestUserNotificationAgent", 60 | "TestRaceAgent", 61 | "TestChatAgent", 62 | "TestOAuthAgent", 63 | "TestMcpJurisdiction", 64 | "TestDestroyScheduleAgent", 65 | "TestScheduleAgent" 66 | ], 67 | "tag": "v1" 68 | } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /site/agents/src/components/_components/background.tsx: -------------------------------------------------------------------------------- 1 | import { useId } from "react"; 2 | 3 | export function BackgroundDots({ 4 | size = 12, 5 | ...props 6 | }: React.ComponentPropsWithoutRef<"pattern"> & { 7 | size?: number; 8 | }) { 9 | const id = useId(); 10 | return ( 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | 29 | export function BackgroundLinesOnly({ size = 64 }) { 30 | return ( 31 |
32 |
33 |
40 |
47 |
48 |
49 |
56 |
63 |
64 |
65 | ); 66 | } 67 | 68 | export function BackgroundLines() { 69 | return ( 70 |
71 | 72 |
73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /.github/workflows/claude.yml: -------------------------------------------------------------------------------- 1 | name: Claude Code 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | pull_request_review_comment: 7 | types: [created] 8 | issues: 9 | types: [opened, assigned] 10 | pull_request_review: 11 | types: [submitted] 12 | 13 | jobs: 14 | claude: 15 | if: | 16 | (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || 17 | (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || 18 | (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || 19 | (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: read 23 | pull-requests: write 24 | issues: write 25 | id-token: write 26 | actions: read # Required for Claude to read CI results on PRs 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@v4 30 | with: 31 | fetch-depth: 1 32 | 33 | - name: Run Claude Code 34 | id: claude 35 | uses: anthropics/claude-code-action@v1 36 | with: 37 | anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} 38 | 39 | # This is an optional setting that allows Claude to read CI results on PRs 40 | additional_permissions: | 41 | actions: read 42 | 43 | # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. 44 | # prompt: 'Update the pull request description to include a summary of changes.' 45 | 46 | # Optional: Add claude_args to customize behavior and configuration 47 | # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md 48 | # or https://docs.claude.com/en/docs/claude-code/cli-reference for available options 49 | # claude_args: '--allowed-tools Bash(gh pr:*)' 50 | -------------------------------------------------------------------------------- /packages/agents/src/mcp/client-transports.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Deprecated transport wrappers 3 | */ 4 | 5 | import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; 6 | import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js"; 7 | import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; 8 | import type { StreamableHTTPClientTransportOptions } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; 9 | 10 | let didWarnAboutSSEEdgeClientTransport = false; 11 | 12 | /** 13 | * @deprecated Use SSEClientTransport from @modelcontextprotocol/sdk/client/sse.js instead. This alias will be removed in the next major version. 14 | */ 15 | export class SSEEdgeClientTransport extends SSEClientTransport { 16 | constructor(url: URL, options: SSEClientTransportOptions) { 17 | super(url, options); 18 | if (!didWarnAboutSSEEdgeClientTransport) { 19 | didWarnAboutSSEEdgeClientTransport = true; 20 | console.warn( 21 | "SSEEdgeClientTransport is deprecated. Use SSEClientTransport from @modelcontextprotocol/sdk/client/sse.js instead. SSEEdgeClientTransport will be removed in the next major version." 22 | ); 23 | } 24 | } 25 | } 26 | 27 | let didWarnAboutStreamableHTTPEdgeClientTransport = false; 28 | 29 | /** 30 | * @deprecated Use StreamableHTTPClientTransport from @modelcontextprotocol/sdk/client/streamableHttp.js instead. This alias will be removed in the next major version. 31 | */ 32 | export class StreamableHTTPEdgeClientTransport extends StreamableHTTPClientTransport { 33 | constructor(url: URL, options: StreamableHTTPClientTransportOptions) { 34 | super(url, options); 35 | if (!didWarnAboutStreamableHTTPEdgeClientTransport) { 36 | didWarnAboutStreamableHTTPEdgeClientTransport = true; 37 | console.warn( 38 | "StreamableHTTPEdgeClientTransport is deprecated. Use StreamableHTTPClientTransport from @modelcontextprotocol/sdk/client/streamableHttp.js instead. StreamableHTTPEdgeClientTransport will be removed in the next major version." 39 | ); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /site/agents/src/components/use-interval.ts: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | https://github.com/donavon/use-interval 4 | 5 | MIT License 6 | 7 | Copyright (c) 2019-present Donavon West 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | */ 28 | 29 | import { useEffect, useRef } from "react"; 30 | 31 | type Delay = number | null; 32 | type TimerHandler = (...args: any[]) => void; 33 | 34 | /** 35 | * Provides a declarative useInterval 36 | * 37 | * @param callback - Function that will be called every `delay` ms. 38 | * @param delay - Number representing the delay in ms. Set to `null` to "pause" the interval. 39 | */ 40 | 41 | const useInterval = (callback: TimerHandler, delay: Delay) => { 42 | const savedCallbackRef = useRef(() => {}); 43 | 44 | useEffect(() => { 45 | savedCallbackRef.current = callback; 46 | }, [callback]); 47 | 48 | useEffect(() => { 49 | const handler = (...args: any[]) => savedCallbackRef.current!(...args); 50 | 51 | if (delay !== null) { 52 | const intervalId = setInterval(handler, delay); 53 | return () => clearInterval(intervalId); 54 | } 55 | }, [delay]); 56 | }; 57 | 58 | export default useInterval; 59 | -------------------------------------------------------------------------------- /examples/cross-domain/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 3 | -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, 4 | Cantarell, sans-serif; 5 | max-width: 800px; 6 | margin: 0 auto; 7 | padding: 20px; 8 | background-color: #f5f5f5; 9 | } 10 | 11 | .chat-container { 12 | background: white; 13 | border-radius: 12px; 14 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 15 | padding: 20px; 16 | margin-bottom: 20px; 17 | } 18 | 19 | .message-form { 20 | display: flex; 21 | gap: 10px; 22 | margin-bottom: 20px; 23 | } 24 | 25 | .message-input { 26 | flex: 1; 27 | padding: 12px; 28 | border: 1px solid #ddd; 29 | border-radius: 6px; 30 | font-size: 16px; 31 | } 32 | 33 | .message-input:focus { 34 | outline: none; 35 | border-color: #0066ff; 36 | } 37 | 38 | button { 39 | background-color: #0066ff; 40 | color: white; 41 | border: none; 42 | border-radius: 6px; 43 | padding: 12px 24px; 44 | font-size: 16px; 45 | cursor: pointer; 46 | transition: background-color 0.2s; 47 | } 48 | 49 | button:hover { 50 | background-color: #0052cc; 51 | } 52 | 53 | .messages-section { 54 | margin-bottom: 30px; 55 | } 56 | 57 | .messages-section h2 { 58 | color: #333; 59 | font-size: 1.2em; 60 | margin-bottom: 15px; 61 | padding-bottom: 8px; 62 | border-bottom: 2px solid #eee; 63 | } 64 | 65 | .message { 66 | padding: 12px 16px; 67 | margin: 8px 0; 68 | border-radius: 8px; 69 | max-width: 80%; 70 | } 71 | 72 | .incoming-message { 73 | background-color: #f0f0f0; 74 | margin-right: auto; 75 | } 76 | 77 | .outgoing-message { 78 | background-color: #0066ff; 79 | color: white; 80 | margin-left: auto; 81 | } 82 | 83 | .timestamp { 84 | font-size: 12px; 85 | color: #666; 86 | margin-top: 4px; 87 | } 88 | 89 | .status-indicator { 90 | display: flex; 91 | align-items: center; 92 | gap: 8px; 93 | color: #666; 94 | font-size: 14px; 95 | margin-bottom: 16px; 96 | } 97 | 98 | .status-dot { 99 | width: 8px; 100 | height: 8px; 101 | border-radius: 50%; 102 | background-color: #22c55e; 103 | } 104 | 105 | .auth-controls { 106 | margin-bottom: 15px; 107 | } 108 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/flows/04 orchestrator.txt: -------------------------------------------------------------------------------- 1 | import { openai } from '@ai-sdk/openai'; 2 | import { generateObject } from 'ai'; 3 | import { z } from 'zod'; 4 | 5 | async function implementFeature(featureRequest: string) { 6 | // Orchestrator: Plan the implementation 7 | const { object: implementationPlan } = await generateObject({ 8 | model: openai('o1'), 9 | schema: z.object({ 10 | files: z.array( 11 | z.object({ 12 | purpose: z.string(), 13 | filePath: z.string(), 14 | changeType: z.enum(['create', 'modify', 'delete']), 15 | }), 16 | ), 17 | estimatedComplexity: z.enum(['low', 'medium', 'high']), 18 | }), 19 | system: 20 | 'You are a senior software architect planning feature implementations.', 21 | prompt: `Analyze this feature request and create an implementation plan: 22 | ${featureRequest}`, 23 | }); 24 | 25 | // Workers: Execute the planned changes 26 | const fileChanges = await Promise.all( 27 | implementationPlan.files.map(async file => { 28 | // Each worker is specialized for the type of change 29 | const workerSystemPrompt = { 30 | create: 31 | 'You are an expert at implementing new files following best practices and project patterns.', 32 | modify: 33 | 'You are an expert at modifying existing code while maintaining consistency and avoiding regressions.', 34 | delete: 35 | 'You are an expert at safely removing code while ensuring no breaking changes.', 36 | }[file.changeType]; 37 | 38 | const { object: change } = await generateObject({ 39 | model: openai('gpt-4o'), 40 | schema: z.object({ 41 | explanation: z.string(), 42 | code: z.string(), 43 | }), 44 | system: workerSystemPrompt, 45 | prompt: `Implement the changes for ${file.filePath} to support: 46 | ${file.purpose} 47 | 48 | Consider the overall feature context: 49 | ${featureRequest}`, 50 | }); 51 | 52 | return { 53 | file, 54 | implementation: change, 55 | }; 56 | }), 57 | ); 58 | 59 | return { 60 | plan: implementationPlan, 61 | changes: fileChanges, 62 | }; 63 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🧠 Cloudflare Agents 2 | 3 | ![npm install agents](assets/npm-install-agents.svg) 4 | 5 | _This project is in active development. Join us in shaping the future of intelligent agents._ 6 | 7 | Welcome to a new paradigm in AI development. Cloudflare Agents provides the foundation for building intelligent, stateful agents that persist, think, and evolve at the edge of the network. 8 | 9 | Read the announcement on the Cloudflare blog: [Making Cloudflare the best platform for building AI Agents](https://blog.cloudflare.com/build-ai-agents-on-cloudflare/) 10 | 11 | ## Vision 12 | 13 | We're creating a framework where AI agents can: 14 | 15 | - Maintain persistent state and memory 16 | - Engage in real-time communication 17 | - Process and learn from interactions 18 | - Operate autonomously at global scale 19 | - Hibernate when idle, awaken when needed 20 | 21 | ## Project Status 22 | 23 | This project is actively evolving. Current focus areas: 24 | 25 | ### Ready for Use 26 | 27 | - Core agent framework with state management 28 | - Real-time WebSocket communication 29 | - HTTP endpoints and routing 30 | - React integration hooks 31 | - Basic AI chat capabilities 32 | 33 | ### In Development 34 | 35 | - Advanced memory systems 36 | - WebRTC for audio/video 37 | - Email integration 38 | - Evaluation framework 39 | - Enhanced observability 40 | - Self-hosting guide 41 | 42 | ## Getting Started 43 | 44 | ### Quick Start 45 | 46 | - Create a new project 47 | 48 | ```bash 49 | npm create cloudflare@latest -- --template cloudflare/agents-starter 50 | ``` 51 | 52 | - Or add to existing project 53 | 54 | ```bash 55 | 56 | npm install agents 57 | ``` 58 | 59 | ## Documentation 60 | 61 | For comprehensive documentation and guides: 62 | 63 | - [Core Framework](packages/agents/README.md) 64 | - [The Anthropic Patterns for building effective agents](guides/anthropic-patterns/README.md) 65 | - [Human in the Loop](guides/human-in-the-loop/README.md) 66 | - [Playground](examples/playground/README.md) 67 | 68 | ## Contributing 69 | 70 | We welcome contributions! Whether it's: 71 | 72 | - New examples 73 | - Documentation improvements 74 | - Bug fixes 75 | - Feature suggestions 76 | 77 | ## License 78 | 79 | MIT License - Build something meaningful. 80 | 81 | --- 82 | -------------------------------------------------------------------------------- /site/ai-playground/README.md: -------------------------------------------------------------------------------- 1 | # Workers AI Playground 2 | 3 | Welcome to the Workers AI Playground! This project is designed to provide a user-friendly interface for interacting with AI models and exploring their capabilities. The playground allows you to connect to Model Context Protocol (MCP) servers, see available tools, and run Workers AI models with ease. 4 | 5 | ## Features 6 | 7 | - **Connect to MCP Servers**: Easily connect to MCP servers to access additional AI capabilities. 8 | - **Dynamic UI**: The interface is built using React and Tailwind CSS, providing a responsive and modern user experience. 9 | - **Tool Management**: View and manage available AI tools when connected to an MCP server. 10 | - **Authentication**: Supports authentication for secure access to MCP servers. 11 | - **Interactive Messaging**: Send messages and receive AI-generated responses in real-time. 12 | 13 | ## Getting Started 14 | 15 | ### Prerequisites 16 | 17 | - Node.js and npm installed on your machine. 18 | 19 | ### Installation 20 | 21 | 1. Clone the repository and install dependencies: 22 | 23 | ```bash 24 | git clone https://github.com/cloudflare/agents.git 25 | npm i 26 | ``` 27 | 28 | 2. Start the development server: 29 | 30 | ```bash 31 | cd site/ai-playground && npm start 32 | ``` 33 | 34 | 3. Open your browser and navigate to `http://localhost:5173` to access the playground. 35 | 36 | ## Configuration 37 | 38 | The project uses Tailwind CSS for styling. You can customize the theme and other configurations in the `tailwind.config.ts` file. 39 | 40 | ## Usage 41 | 42 | - **Connect to a Server**: Enter the MCP server URL and click "Connect" to establish a connection. 43 | - **Manage Tools**: Once connected, view and interact with available AI tools. 44 | - **Send Messages**: Use the input field to send messages and receive AI responses. 45 | 46 | ## Contributing 47 | 48 | Contributions are welcome! Please fork the repository and submit a pull request with your changes. 49 | 50 | ## License 51 | 52 | This project is licensed under the MIT License. 53 | 54 | ## Acknowledgments 55 | 56 | - Thanks to the contributors and the open-source community for their support and collaboration. 57 | 58 | Enjoy exploring the capabilities of AI with the Workers AI Playground! 59 | -------------------------------------------------------------------------------- /openai-sdk/chess-app/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createMcpHandler } from "agents/mcp"; 2 | import { routeAgentRequest } from "agents"; 3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 4 | import { env } from "cloudflare:workers"; 5 | 6 | const getWidgetHtml = async (host: string) => { 7 | let html = await (await env.ASSETS.fetch("http://localhost/")).text(); 8 | html = html.replace( 9 | "", 10 | `` 11 | ); 12 | return html; 13 | }; 14 | 15 | const server = new McpServer({ name: "Chess", version: "v1.0.0" }); 16 | 17 | // register a UI resource 18 | server.registerResource( 19 | "chess", 20 | "ui://widget/index.html", 21 | {}, 22 | async (_uri, extra) => { 23 | console.log("HEADERS", extra.requestInfo?.headers); 24 | return { 25 | contents: [ 26 | { 27 | uri: "ui://widget/index.html", 28 | mimeType: "text/html+skybridge", 29 | text: await getWidgetHtml(extra.requestInfo?.headers.host as string) 30 | } 31 | ] 32 | }; 33 | } 34 | ); 35 | 36 | // register the tool to render the UI resource 37 | server.registerTool( 38 | "playChess", 39 | { 40 | title: "Renders a chess game menu, ready to start or join a game.", 41 | annotations: { readOnlyHint: true }, // Tells ChatGPT that this tool is safe 42 | _meta: { 43 | "openai/outputTemplate": "ui://widget/index.html", 44 | "openai/toolInvocation/invoking": "Opening chess widget", 45 | "openai/toolInvocation/invoked": "Chess widget opened" 46 | } 47 | }, 48 | async () => { 49 | return { 50 | content: [ 51 | { type: "text" as const, text: "Successfully rendered chess game menu" } 52 | ] 53 | }; 54 | } 55 | ); 56 | 57 | // create the MCP handler to talk to our server 58 | const mcpHandler = createMcpHandler(server); 59 | 60 | export default { 61 | async fetch(req: Request, env: Env, ctx: ExecutionContext) { 62 | const url = new URL(req.url); 63 | if (url.pathname.startsWith("/mcp")) return mcpHandler(req, env, ctx); 64 | 65 | return ( 66 | (await routeAgentRequest(req, env)) ?? 67 | new Response("Not found", { status: 404 }) 68 | ); 69 | } 70 | }; 71 | 72 | export { ChessGame } from "./chess"; 73 | -------------------------------------------------------------------------------- /examples/playground/src/components/Chat.css: -------------------------------------------------------------------------------- 1 | /* Chat Wrapper Styles */ 2 | .chat-wrapper { 3 | display: flex; 4 | flex-direction: column; 5 | height: 100%; 6 | padding: 20px; 7 | } 8 | 9 | .tab-bar { 10 | display: flex; 11 | gap: 4px; 12 | margin-bottom: 20px; 13 | } 14 | 15 | .tab { 16 | padding: 10px 20px; 17 | border: none; 18 | border-radius: 8px; 19 | background-color: #f0f0f0; 20 | color: #666; 21 | cursor: pointer; 22 | transition: all 0.2s ease; 23 | font-size: 14px; 24 | font-weight: 500; 25 | } 26 | 27 | .tab:hover { 28 | background-color: #e0e0e0; 29 | color: #333; 30 | } 31 | 32 | .tab.active { 33 | background-color: #007bff; 34 | color: white; 35 | } 36 | 37 | /* Chat Room Styles */ 38 | .chat-container { 39 | display: flex; 40 | flex-direction: column; 41 | height: 80vh; 42 | max-width: 800px; 43 | margin: 0 auto; 44 | padding: 20px; 45 | background-color: #ffffff; 46 | border-radius: 12px; 47 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 48 | width: 100%; 49 | } 50 | 51 | .messages-wrapper { 52 | flex: 1; 53 | overflow-y: auto; 54 | padding: 20px; 55 | margin-bottom: 20px; 56 | } 57 | 58 | .message { 59 | margin-bottom: 16px; 60 | padding: 12px; 61 | border-radius: 8px; 62 | background-color: #f5f5f5; 63 | color: #333333; 64 | } 65 | 66 | .message-content { 67 | margin-top: 8px; 68 | line-height: 1.5; 69 | white-space: pre-wrap; 70 | } 71 | 72 | .chat-input { 73 | width: 100%; 74 | padding: 12px; 75 | border: 2px solid #e0e0e0; 76 | border-radius: 8px; 77 | font-size: 16px; 78 | background-color: #ffffff; 79 | color: #333333; 80 | transition: border-color 0.2s ease; 81 | box-sizing: border-box; 82 | } 83 | 84 | .chat-input:focus { 85 | outline: none; 86 | border-color: #007bff; 87 | } 88 | 89 | .controls-container { 90 | display: flex; 91 | justify-content: flex-end; 92 | gap: 12px; 93 | padding: 12px; 94 | } 95 | 96 | .clear-history { 97 | padding: 8px 16px; 98 | border: none; 99 | border-radius: 8px; 100 | background-color: #f0f0f0; 101 | color: #333333; 102 | cursor: pointer; 103 | transition: background-color 0.2s ease; 104 | } 105 | 106 | .clear-history:hover { 107 | background-color: #e0e0e0; 108 | } 109 | -------------------------------------------------------------------------------- /packages/agents/src/tests/schedule.test.ts: -------------------------------------------------------------------------------- 1 | import { env } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | import type { Env } from "./worker"; 4 | import { getAgentByName } from ".."; 5 | 6 | declare module "cloudflare:test" { 7 | interface ProvidedEnv extends Env {} 8 | } 9 | 10 | describe("schedule operations", () => { 11 | describe("cancelSchedule", () => { 12 | it("should return false when cancelling a non-existent schedule", async () => { 13 | const agentStub = await getAgentByName( 14 | env.TestScheduleAgent, 15 | "cancel-nonexistent-test" 16 | ); 17 | 18 | // This should NOT throw, and should return false 19 | const result = await agentStub.cancelScheduleById("non-existent-id"); 20 | expect(result).toBe(false); 21 | }); 22 | 23 | it("should return true when cancelling an existing schedule", async () => { 24 | const agentStub = await getAgentByName( 25 | env.TestScheduleAgent, 26 | "cancel-existing-test" 27 | ); 28 | 29 | // Create a schedule first (60 seconds delay) 30 | const scheduleId = await agentStub.createSchedule(60); 31 | 32 | // Cancel should succeed and return true 33 | const result = await agentStub.cancelScheduleById(scheduleId); 34 | expect(result).toBe(true); 35 | }); 36 | }); 37 | 38 | describe("getSchedule", () => { 39 | it("should return undefined when getting a non-existent schedule", async () => { 40 | const agentStub = await getAgentByName( 41 | env.TestScheduleAgent, 42 | "get-nonexistent-test" 43 | ); 44 | 45 | const result = await agentStub.getScheduleById("non-existent-id"); 46 | expect(result).toBeUndefined(); 47 | }); 48 | 49 | it("should return schedule when getting an existing schedule", async () => { 50 | const agentStub = await getAgentByName( 51 | env.TestScheduleAgent, 52 | "get-existing-test" 53 | ); 54 | 55 | // Create a schedule first (60 seconds delay) 56 | const scheduleId = await agentStub.createSchedule(60); 57 | 58 | const result = await agentStub.getScheduleById(scheduleId); 59 | expect(result).toBeDefined(); 60 | expect(result?.id).toBe(scheduleId); 61 | expect(result?.callback).toBe("testCallback"); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /site/agents/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "../styles/globals.css"; 3 | 4 | interface Props { 5 | title?: string; 6 | description?: string; 7 | } 8 | 9 | const { 10 | title = "Cloudflare Agents", 11 | description = "Build agents on Cloudflare—the platform designed for durable execution, serverless inference, and pricing that scales up (and down)." 12 | } = Astro.props; 13 | --- 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {title} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 89 | 90 | -------------------------------------------------------------------------------- /site/ai-playground/src/components/Icons.tsx: -------------------------------------------------------------------------------- 1 | export const TrashIcon = () => ( 2 | 9 | Trash 10 | 15 | 22 | 29 | 36 | 37 | ); 38 | 39 | export const SparkleIcon = () => ( 40 | 47 | Sparkle 48 | 52 | 56 | 60 | 61 | ); 62 | -------------------------------------------------------------------------------- /site/agents/src/server/index.ts: -------------------------------------------------------------------------------- 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker"; 3 | import { z } from "zod"; 4 | import { createMcpHandler } from "agents/mcp"; 5 | import { fetchAndBuildIndex, formatResults } from "./utils"; 6 | import { search } from "@orama/orama"; 7 | import { Effect } from "effect"; 8 | 9 | // TODO: instrument this server for observability 10 | const mcpServer = new McpServer( 11 | { 12 | name: "agents-mcp", 13 | version: "0.0.1" 14 | }, 15 | { 16 | capabilities: {}, 17 | jsonSchemaValidator: new CfWorkerJsonSchemaValidator() 18 | } 19 | ); 20 | 21 | const inputSchema = { 22 | query: z 23 | .string() 24 | .describe( 25 | "query string to search for eg. 'agent hibernate', 'schedule tasks'" 26 | ), 27 | k: z.number().optional().default(5).describe("number of results to return") 28 | }; 29 | 30 | mcpServer.registerTool( 31 | "search-agent-docs", 32 | { 33 | description: 34 | "Token efficient search of the Cloudflare Agents SDK documentation", 35 | inputSchema 36 | }, 37 | async ({ query, k }) => { 38 | const searchEffect = Effect.gen(function* () { 39 | console.log({ query, k }); 40 | const term = query.trim(); 41 | 42 | const docsDb = yield* fetchAndBuildIndex; 43 | 44 | const result = search(docsDb, { term, limit: k }); 45 | const searchResult = yield* result instanceof Promise 46 | ? Effect.promise(() => result) 47 | : Effect.succeed(result); 48 | 49 | return { 50 | content: [ 51 | { 52 | type: "text" as const, 53 | text: formatResults(searchResult, term, k) 54 | } 55 | ] 56 | }; 57 | }).pipe( 58 | Effect.catchAll((error) => { 59 | console.error(error); 60 | return Effect.succeed({ 61 | content: [ 62 | { 63 | type: "text" as const, 64 | text: `There was an error with the search tool. Please try again later.` 65 | } 66 | ] 67 | }); 68 | }) 69 | ); 70 | 71 | return await Effect.runPromise(searchEffect); 72 | } 73 | ); 74 | 75 | export default { 76 | async fetch(request: Request, env: Env, ctx: ExecutionContext) { 77 | return createMcpHandler(mcpServer)(request, env, ctx); 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /examples/mcp-client/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 3 | -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, 4 | Cantarell, sans-serif; 5 | max-width: 800px; 6 | margin: 0 auto; 7 | padding: 20px; 8 | background-color: #f5f5f5; 9 | } 10 | 11 | .container { 12 | background: white; 13 | border-radius: 12px; 14 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 15 | padding: 20px; 16 | margin-bottom: 20px; 17 | } 18 | 19 | .mcp-form { 20 | display: flex; 21 | gap: 10px; 22 | margin-bottom: 20px; 23 | } 24 | 25 | .mcp-input { 26 | flex: 1; 27 | padding: 12px; 28 | border: 1px solid #ddd; 29 | border-radius: 6px; 30 | font-size: 16px; 31 | } 32 | 33 | .mcp-input.name { 34 | flex: 0; 35 | width: 150px; 36 | } 37 | 38 | .mcp-input:focus { 39 | outline: none; 40 | border-color: #0066ff; 41 | } 42 | 43 | button { 44 | background-color: #0066ff; 45 | color: white; 46 | border: none; 47 | border-radius: 6px; 48 | padding: 12px 24px; 49 | font-size: 16px; 50 | cursor: pointer; 51 | transition: background-color 0.2s; 52 | } 53 | 54 | button:hover { 55 | background-color: #0052cc; 56 | } 57 | 58 | .mcp-section { 59 | margin-bottom: 30px; 60 | } 61 | 62 | .mcp-section h2 { 63 | color: #333; 64 | font-size: 1.2em; 65 | margin-bottom: 15px; 66 | padding-bottom: 8px; 67 | border-bottom: 2px solid #eee; 68 | } 69 | 70 | .mcp-server { 71 | padding: 8px 8px; 72 | margin: 8px 0; 73 | border-radius: 8px; 74 | max-width: 100%; 75 | display: flex; 76 | flex-direction: row; 77 | background-color: #f0f0f0; 78 | margin-right: auto; 79 | justify-content: space-between; 80 | } 81 | 82 | .status-indicator { 83 | display: flex; 84 | align-items: center; 85 | gap: 8px; 86 | color: #666; 87 | font-size: 14px; 88 | margin-top: 6px; 89 | } 90 | 91 | .status-dot { 92 | width: 8px; 93 | height: 8px; 94 | border-radius: 50%; 95 | background-color: #666; 96 | } 97 | 98 | .status-dot.connected { 99 | background-color: #22c55e; 100 | } 101 | 102 | .code { 103 | font-family: monospace; 104 | background-color: #f0f0f0; 105 | padding: 8px; 106 | margin: 8px 0; 107 | border-radius: 4px; 108 | } 109 | 110 | .mcp-servers { 111 | margin-top: 8px; 112 | } 113 | 114 | b { 115 | margin-bottom: 4px; 116 | display: inline-block; 117 | } 118 | -------------------------------------------------------------------------------- /examples/mcp-worker-authenticated/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createMcpHandler, getMcpAuthContext } from "agents/mcp"; 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 3 | import { z } from "zod"; 4 | import { OAuthProvider } from "@cloudflare/workers-oauth-provider"; 5 | import { AuthHandler } from "./auth-handler"; 6 | 7 | const server = new McpServer({ 8 | name: "Authenticated MCP Server", 9 | version: "1.0.0" 10 | }); 11 | 12 | server.registerTool( 13 | "hello", 14 | { 15 | description: "Returns a greeting message", 16 | inputSchema: { name: z.string().optional() } 17 | }, 18 | async ({ name }) => { 19 | const auth = getMcpAuthContext(); 20 | const username = auth?.props?.username as string | undefined; 21 | 22 | return { 23 | content: [ 24 | { 25 | text: `Hello, ${name ?? username ?? "World"}!`, 26 | type: "text" 27 | } 28 | ] 29 | }; 30 | } 31 | ); 32 | 33 | server.registerTool( 34 | "whoami", 35 | { 36 | description: "Returns information about the authenticated user" 37 | }, 38 | async () => { 39 | const auth = getMcpAuthContext(); 40 | 41 | if (!auth) { 42 | return { 43 | content: [ 44 | { 45 | text: "No authentication context available", 46 | type: "text" as const 47 | } 48 | ] 49 | }; 50 | } 51 | 52 | return { 53 | content: [ 54 | { 55 | text: JSON.stringify( 56 | { 57 | userId: auth.props?.userId, 58 | username: auth.props?.username, 59 | email: auth.props?.email 60 | }, 61 | null, 62 | 2 63 | ), 64 | type: "text" as const 65 | } 66 | ] 67 | }; 68 | } 69 | ); 70 | 71 | /** 72 | * API Handler - handles authenticated MCP requests 73 | * This handler will receive requests that have a valid access token 74 | */ 75 | const apiHandler = { 76 | async fetch(request: Request, env: unknown, ctx: ExecutionContext) { 77 | return createMcpHandler(server)(request, env, ctx); 78 | } 79 | }; 80 | 81 | export default new OAuthProvider({ 82 | authorizeEndpoint: "/authorize", 83 | tokenEndpoint: "/oauth/token", 84 | clientRegistrationEndpoint: "/oauth/register", 85 | 86 | apiRoute: "/mcp", 87 | apiHandler: apiHandler, 88 | 89 | //@ts-expect-error 90 | defaultHandler: AuthHandler 91 | }); 92 | -------------------------------------------------------------------------------- /packages/agents/src/tests-d/typed-use-agent.test-d.ts: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/correctness/useHookAtTopLevel: testing types */ 2 | import type { env } from "cloudflare:workers"; 3 | import { Agent } from ".."; 4 | import { useAgent } from "../react"; 5 | 6 | declare class A extends Agent { 7 | prop: string; 8 | f1: () => number; 9 | f2: (a: string) => void; 10 | f3: (a: number, b: string) => Promise; 11 | f4: (a?: string) => void; 12 | f5: (a: string | undefined) => void; 13 | f6: () => Promise; 14 | f7: (a: string | undefined, b: number) => Promise; 15 | f8: (a: string | undefined, b?: number) => Promise; 16 | nonSerializableParams: (a: string, b: { c: Date }) => void; 17 | nonSerializableReturn: (a: string) => Date; 18 | } 19 | 20 | // @ts-expect-error state doesn't match type A state 21 | const _a2 = useAgent({ 22 | agent: "test" 23 | }); 24 | 25 | const a1 = useAgent({ 26 | agent: "test" 27 | }); 28 | 29 | a1.call("f1") satisfies Promise; 30 | // @ts-expect-error 31 | a1.call("f1", [1]) satisfies Promise; 32 | 33 | a1.call("f2", ["test"]) satisfies Promise; 34 | // @ts-expect-error should receive a [string] 35 | a1.call("f2"); 36 | // @ts-expect-error 37 | a1.call("f2", [1]); 38 | 39 | a1.call("f3", [1, "test"]) satisfies Promise; 40 | // @ts-expect-error should receive a [number, string] 41 | a1.call("f3") satisfies Promise; 42 | // @ts-expect-error 43 | a1.call("f3", [1]) satisfies Promise; 44 | 45 | a1.call("f4") satisfies Promise; 46 | a1.call("f4", []) satisfies Promise; 47 | a1.call("f4", [undefined]) satisfies Promise; 48 | 49 | a1.call("f5") satisfies Promise; 50 | // @ts-expect-error should receive a [string | undefined] 51 | a1.call("f5", []) satisfies Promise; 52 | a1.call("f5", [undefined]) satisfies Promise; 53 | 54 | a1.call("f6") satisfies Promise; 55 | 56 | // @ts-expect-error should receive a [string | undefined, number] 57 | a1.call("f7") satisfies Promise; 58 | a1.call("f7", [undefined, 1]) satisfies Promise; 59 | 60 | a1.call("f8") satisfies Promise; 61 | a1.call("f8", [undefined, undefined]) satisfies Promise; 62 | 63 | // @ts-expect-error Date parameter not serializable 64 | a1.call("nonSerializableParams", ["test", { c: new Date() }]); 65 | // @ts-expect-error Date return not serializable 66 | a1.call("nonSerializableReturn", ["test"]); 67 | -------------------------------------------------------------------------------- /site/ai-playground/src/components/LocalhostWarningModal.tsx: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/a11y/noStaticElementInteractions: it's fine */ 2 | import ShellCommand from "./ShellCommand"; 3 | 4 | const LocalhostWarningModal = ({ 5 | visible, 6 | handleHide 7 | }: { 8 | visible: boolean; 9 | handleHide: (e: React.MouseEvent) => void; 10 | }) => { 11 | if (!visible) return null; 12 | 13 | return ( 14 |
18 |
{ 20 | e.stopPropagation(); 21 | }} 22 | className="bg-white shadow-xl rounded-md md:max-w-2xl w-full p-6" 23 | > 24 |

25 | Localhost is not allowed 26 |
30 | × 31 |
32 |

33 |

34 | MCP servers are connected server-side. Localhost URLs cannot be 35 | accessed. 36 |

37 | 38 |
39 |

40 | Use Cloudflare Tunnel for Local Development 41 |

42 | 43 |
44 | 48 | 49 | 53 | 54 | 58 |
59 | 60 |

61 | Copy the tunnel URL (e.g., https://xyz.trycloudflare.com) and use it 62 | as your MCP server endpoint. Note you will need to add the /mcp 63 | path. 64 |

65 |
66 |
67 |
68 | ); 69 | }; 70 | 71 | export default LocalhostWarningModal; 72 | -------------------------------------------------------------------------------- /guides/anthropic-patterns/src/flows/03 parallel.txt: -------------------------------------------------------------------------------- 1 | import { openai } from '@ai-sdk/openai'; 2 | import { generateText, generateObject } from 'ai'; 3 | import { z } from 'zod'; 4 | 5 | // Example: Parallel code review with multiple specialized reviewers 6 | async function parallelCodeReview(code: string) { 7 | const model = openai('gpt-4o'); 8 | 9 | // Run parallel reviews 10 | const [securityReview, performanceReview, maintainabilityReview] = 11 | await Promise.all([ 12 | generateObject({ 13 | model, 14 | system: 15 | 'You are an expert in code security. Focus on identifying security vulnerabilities, injection risks, and authentication issues.', 16 | schema: z.object({ 17 | vulnerabilities: z.array(z.string()), 18 | riskLevel: z.enum(['low', 'medium', 'high']), 19 | suggestions: z.array(z.string()), 20 | }), 21 | prompt: `Review this code: 22 | ${code}`, 23 | }), 24 | 25 | generateObject({ 26 | model, 27 | system: 28 | 'You are an expert in code performance. Focus on identifying performance bottlenecks, memory leaks, and optimization opportunities.', 29 | schema: z.object({ 30 | issues: z.array(z.string()), 31 | impact: z.enum(['low', 'medium', 'high']), 32 | optimizations: z.array(z.string()), 33 | }), 34 | prompt: `Review this code: 35 | ${code}`, 36 | }), 37 | 38 | generateObject({ 39 | model, 40 | system: 41 | 'You are an expert in code quality. Focus on code structure, readability, and adherence to best practices.', 42 | schema: z.object({ 43 | concerns: z.array(z.string()), 44 | qualityScore: z.number().min(1).max(10), 45 | recommendations: z.array(z.string()), 46 | }), 47 | prompt: `Review this code: 48 | ${code}`, 49 | }), 50 | ]); 51 | 52 | const reviews = [ 53 | { ...securityReview.object, type: 'security' }, 54 | { ...performanceReview.object, type: 'performance' }, 55 | { ...maintainabilityReview.object, type: 'maintainability' }, 56 | ]; 57 | 58 | // Aggregate results using another model instance 59 | const { text: summary } = await generateText({ 60 | model, 61 | system: 'You are a technical lead summarizing multiple code reviews.', 62 | prompt: `Synthesize these code review results into a concise summary with key actions: 63 | ${JSON.stringify(reviews, null, 2)}`, 64 | }); 65 | 66 | return { reviews, summary }; 67 | } --------------------------------------------------------------------------------