Hoy presentamos Project Think: la próxima generación del SDK de agentes. Project Think es un conjunto de nuevas primitivas para crear agentes de larga duración (ejecución duradera, subagentes, ejecución de código en espacio aislado, sesiones continuas) y una clase base con opiniones propias que los conecta a todos. Puedes utilizar las primitivas para crear exactamente lo que necesitas, o utilizar la clase base para empezar rápidamente.
Algo sucedió a principios de este año que cambió nuestra forma de pensar sobre la IA. Herramientas como Pi, OpenClaw, Claude Code y Codex demostraron una idea simple pero poderosa: si le das a un LLM la capacidad de leer archivos, escribir código, ejecutarlo y recordar lo que aprendió, obtendrás algo que se parece menos a una herramienta de desarrollador y más a un asistente de propósito general.
Estos agentes de programación ya no solo escriben código. Las personas las utilizan para gestionar calendarios, analizar conjuntos de datos, negociar compras, declarar impuestos y automatizar flujos de trabajo empresariales. El patrón es siempre el mismo: el agente lee el contexto, razona al respecto, escribe código para actuar, observa el resultado e itera. El código es el medio universal de acción.
Nuestro equipo ha estado utilizando estos agentes de codificación todos los días. Y seguíamos chocando contra las mismas paredes:
Solo se ejecutan en tu portátil o en un costoso VPS: no se comparte, no se colabora ni se transfiere entre dispositivos.
Son costosos cuando están inactivos: un costo mensual fijo, ya sea que el agente esté trabajando o no. Escala eso a un equipo o a una empresa, y se acumula rápidamente.
Requieren gestión y configuración manual: instalación de dependencias, gestión de actualizaciones, configuración de identidad y datos confidenciales.
Y hay un problema estructural más profundo. Las aplicaciones tradicionales dan servicio a muchos usuarios desde una única instancia. Como mencionamos en nuestra publicación de bienvenida a Agents Week, los agentes son uno a uno. Cada agente es una instancia única, para un solo usuario, ejecutando una sola tarea. Un restaurante tiene un menú y una cocina optimizada para producir platos en grandes cantidades. Un agente es más como un chef personal: diferentes ingredientes, diferentes técnicas, diferentes herramientas cada vez.
Eso cambia fundamentalmente la lógica de la escalabilidad. Si cien millones de personas que gestionan la información utilizaran cada uno un asistente autónomo a una concurrencia incluso moderada, se necesitaría capacidad para decenas de millones de sesiones simultáneas. Con los costos actuales por contenedor, eso es insostenible. Necesitamos una base diferente.
Eso es lo que hemos estado desarrollando.
Presentación de Project Think
Project Think incluye un conjunto de primitivas nuevas para el SDK de agentes:
Ejecución duradera con fibras: recuperación de fallos, puntos de control, mantenimiento automático de la actividad.
Subagentes: agentes secundarios aislados con su propio SQLite y RPC tipificado.
Sesiones continuas: mensajes con estructura de árbol, bifurcación, compactación, búsqueda de texto completo.
Ejecución de código en espacio aislado: Dynamic Workers, codemode, resolución de npm en tiempo de ejecución.
La escalera de ejecución: espacio de trabajo, aislamiento, npm, navegador, espacio seguro.
Extensiones de creación propia: agentes que escriben sus propias herramientas en tiempo de ejecución.
Cada uno de estos se puede utilizar directamente con la clase base Agent. Crea exactamente lo que necesitas con las primitivas, o utiliza la clase base Think para empezar rápidamente. Veamos qué hace cada uno.
Agentes de larga duración
Los agentes, como se los conoce hoy, son efímeros. Se ejecutan durante una sesión, están vinculados a un solo proceso o dispositivo, y luego desaparecen. Un agente de codificación que muere cuando tu laptop entra en modo de suspensión, eso es una herramienta. Un agente que persiste, que puede activarse a pedido, continuar trabajando después de las interrupciones y transferir el estado sin depender de tu tiempo de ejecución local, comienza a parecerse a una infraestructura. Y cambia por completo el modelo de escalamiento de los agentes.
El SDK de agentes se basa en Durable Objects para dar a cada agente una identidad, un estado permanente y la capacidad de reactivarse al recibir un mensaje. Este es el modelo de actor: cada agente es una entidad direccionable con su propia base de datos SQLite. No consume recursos de cómputo cuando está en hibernación. Cuando algo sucede (una solicitud HTTP, un mensaje WebSocket, una alarma programada, un correo electrónico entrante), la plataforma activa al agente, carga su estado y le pasa el evento. El agente hace su trabajo y luego vuelve a dormir.
| Máquinas virtuales/contenedores | Objetos duraderos |
|---|
Costo inactivo | Costo total de cálculo, siempre | Cero (hibernado) |
Escalamiento | Proporciona y gestiona la capacidad | Automático, por agente |
Estado | Se requiere una base de datos externa | SQLite integrado |
Recuperación | Los construyes (gestores de procesos, comprobaciones de estado) | La plataforma se reinicia, el estado se mantiene |
Identidad/Enrutamiento | Los construyes (equilibradores de carga, sesiones persistentes) | Integrado (nombre → agente) |
10.000 agentes, cada uno activo el 1 % del tiempo | 10.000 instancias siempre activas | ~100 activos en cualquier momento |
Esto cambia la economía de la gestión de agentes a escala. En lugar de "un costoso agente por usuario avanzado", puedes crear "un agente por cliente" o "un agente por tarea" o "un agente por hilo de correo electrónico". El costo marginal de generar un nuevo agente es prácticamente cero.
Cómo sobrevivir a los bloqueos: ejecución duradera con fibras
Una llamada de LLM dura 30 segundos. Un ciclo de agente de múltiples turnos puede ejecutarse durante mucho más tiempo. En cualquier momento durante esa ventana, el entorno de ejecución puede desaparecer: una implementación, un reinicio de la plataforma, alcanzar límites de recursos. La conexión ascendente con el proveedor del modelo se corta de forma permanente, se pierde el estado en memoria y los clientes conectados ven que la transmisión se detiene sin explicación.
runFiber() resuelve esto. Una fibra es una invocación de función duradera: registrada en SQLite antes de que comience la ejecución, se puede guardar en cualquier punto a través de stash(), y se puede recuperar al reiniciar mediante onFiberRecovered.
import { Agent } from "agents";
export class ResearchAgent extends Agent {
async startResearch(topic: string) {
void this.runFiber("research", async (ctx) => {
const findings = [];
for (let i = 0; i < 10; i++) {
const result = await this.callLLM(`Research step ${i}: ${topic}`);
findings.push(result);
// Checkpoint: if evicted, we resume from here
ctx.stash({ findings, step: i, topic });
this.broadcast({ type: "progress", step: i });
}
return { findings };
});
}
async onFiberRecovered(ctx) {
if (ctx.name === "research" && ctx.snapshot) {
const { topic } = ctx.snapshot;
await this.startResearch(topic);
}
}
}
El SDK mantiene activo al agente automáticamente durante la ejecución de la fibra, sin necesidad de una configuración especial. Para el trabajo medido en minutos, keepAlive()/keepAliveWhile() evita la expulsión durante el trabajo activo. Para operaciones más largas (canalizaciones de integración continua (CI), revisiones de diseño, generación de video), el agente comienza el trabajo, persiste la ID del trabajo, hiberna y se activa en la llamada de retorno.
Delegación de trabajo: subagentes a través de Facets
Un solo agente no debería hacerlo todo por sí mismo. Subagentes son secundarios a Durable Objects ubicados junto al principal a través de Facets, cada uno con su propio SQLite aislado y contexto de ejecución:
import { Agent } from "agents";
export class ResearchAgent extends Agent {
async search(query: string) { /* ... */ }
}
export class ReviewAgent extends Agent {
async analyze(query: string) { /* ... */ }
}
export class Orchestrator extends Agent {
async handleTask(task: string) {
const researcher = await this.subAgent(ResearchAgent, "research");
const reviewer = await this.subAgent(ReviewAgent, "review");
const [research, review] = await Promise.all([
researcher.search(task),
reviewer.analyze(task)
]);
return this.synthesize(research, review);
}
}
Los subagentes están aislados a nivel de almacenamiento. Cada uno tiene su propia base de datos SQLite, y no hay un intercambio implícito de datos entre ellos. Esto lo aplica el tiempo de ejecución, donde la latencia RPC del subagente es una llamada a una función. TypeScript detecta el uso indebido en tiempo de compilación.
Conversaciones que persisten: la API de sesión
Los agentes que se ejecutan durante días o semanas necesitan más que la lista básica de mensajes habitual. La API de sesión experimental modela esto explícitamente. Disponibles en la clase base Agent, las conversaciones se almacenan como árboles, donde cada mensaje tiene un parent_id. Esto permite la bifurcación (explorar una alternativa sin perder la ruta original), la compactación no destructiva (resumir los mensajes más antiguos en lugar de eliminarlos) y la búsqueda de texto completo en el historial de conversaciones a través de FTS5.
import { Agent } from "agents";
import { Session, SessionManager } from "agents/experimental/memory/session";
export class MyAgent extends Agent {
sessions = SessionManager.create(this);
async onStart() {
const session = this.sessions.create("main");
const history = session.getHistory();
const forked = this.sessions.fork(session.id, messageId, "alternative-approach");
}
}
La sesión se puede utilizar directamente con Agent, y es la capa de almacenamiento sobre la que se basa la clase base Think.
La llamada de herramientas convencional tiene una forma incómoda. El modelo llama a una herramienta, extrae el resultado a través de la ventana de contexto, llama a otra herramienta, la recupera, y así sucesivamente. A medida que crece la superficie de la herramienta, esto se vuelve costoso y complicado. Cien archivos significan cien viajes de ida y vuelta a través del modelo.
Pero los modelos son mejores para escribir código para usar un sistema que para jugar el juego de llamada de herramientas. Esta es la base de @cloudflare/codemode: en lugar de llamadas de herramientas secuenciales, el LLM escribe un único programa que se encarga de toda la tarea.
// The LLM writes this. It runs in a sandboxed Dynamic Worker.
const files = await tools.find({ pattern: "**/*.ts" });
const results = [];
for (const file of files) {
const content = await tools.read({ path: file });
if (content.includes("TODO")) {
results.push({ file, todos: content.match(/\/\/ TODO:.*/g) });
}
}
return results;
En lugar de 100 viajes de ida y vuelta al modelo, solo tienes que ejecutar un único programa. Esto conduce a un menor uso de tokens, una ejecución más rápida y mejores resultados. El servidor MCP de la API de Cloudflare demuestra esto a gran escala. Exponemos solo dos herramientas (search() y execute()), que consumen ~1.000 tokens, frente a ~1,17 millones de tokens para el equivalente ingenuo de herramienta por punto final. Esta es una reducción del 99,9 %.
La primitiva que faltaba: espacios aislados seguros
Una vez que aceptas que los modelos deben escribir el código en nombre de los usuarios, la pregunta es: ¿dónde se ejecuta ese código? No eventualmente, no después de que un equipo de producto lo convierta en un elemento de la hoja de ruta. En este momento, para este usuario, en este sistema, con permisos estrictamente definidos.
Los Dynamic Workers son ese espacio aislado (sandbox). Un nuevo aislamiento de V8 se activaba en tiempo de ejecución, en milisegundos, con unos pocos megabytes de memoria. Eso es aproximadamente 100 veces más rápido y hasta 100 veces más eficiente en términos de memoria que un contenedor. Puedes iniciar una nueva para cada solicitud, ejecutar un fragmento de código y desecharlo.
La elección de diseño clave es el modelo de capacidad. En lugar de comenzar con una máquina de propósito general e intentar restringirla, Dynamic Workers comienza casi sin autoridad ambiental (globalOutbound: null, sin acceso a la red) y el desarrollador otorga capacidades explícitamente, recurso por recurso, a través de enlaces. Pasamos de preguntarnos "¿cómo evitamos que esto haga demasiado?" a "¿qué queremos que sea capaz de hacer exactamente?"
Esta es la pregunta correcta para la infraestructura de agentes.
La escalera de la ejecución
Este modelo de capacidad conduce naturalmente a un espectro de entornos informáticos, una escalera de ejecución por la que el agente escala según sea necesario:
El nivel 0 es el espacio de trabajo, un sistema de archivos virtual duradero respaldado por SQLite y R2. Leer, escribir, editar, buscar, grep, diff. Con tecnología de @cloudflare/shell.
El nivel 1 es un Dynamic Worker: JavaScript generado por LLM que se ejecuta en un espacio aislado sin acceso a la red. Con tecnología de @cloudflare/codemode.
El nivel 2 agrega npm. @cloudflare/worker-bundler obtiene los paquetes del registro, los agrupa con esbuild y carga el resultado en el Dynamic Worker. El agente escribe import { z } from "zod" y simplemente funciona.
El nivel 3 es un navegador sin interfaz gráfica a través de Cloudflare Browser Run. Navegar, hacer clic, extraer, capturar la pantalla. Útil cuando el servicio aún no admite agentes a través de MCP o API.
El nivel 4 es un Cloudflare Sandbox configurado con tus cadenas de herramientas, repositorios y dependencias: git clone, npm test, cargo build, sincronizado bidireccionalmente con el Workspace.
El principio clave del diseño: el agente debe ser útil solo en el nivel 0, donde cada nivel es un adicional. El usuario puede agregar capacidades sobre la marcha.
Bloques de construcción, no un marco
Todas estas primitivas están disponibles como paquetes independientes. Dynamic Workers, @cloudflare/codemode, @cloudflare/worker-bundler y @cloudflare/shell (un sistema de archivos duradero con herramientas) se pueden usar directamente con la clase base de Agente. Puedes combinarlos para brindar a cualquier agente un espacio de trabajo, ejecución de código y resolución de paquetes en tiempo de ejecución sin adoptar un marco de trabajo predefinido.
Esta es la infraestructura completa para crear agentes en Cloudflare:
Funciones | Qué hace | Desarrollado por |
|---|
Aislamiento por agente | Cada agente es su propio mundo | Durable Objects (DOs) |
Costo cero cuando está inactivo | USD 0 hasta que el agente se active | DO Hibernación |
Estado permanente | Almacenamiento transaccional consultable | DO SQLite |
Sistema de archivos duradero | Archivos que sobreviven a los reinicios | Espacio de trabajo (SQLite + R2) |
Ejecución de código en sandbox | Ejecuta el código generado por el LLM de forma segura | Dynamic Workers + @cloudflare/codemode |
Dependencias en tiempo de ejecución | import * from react simplemente funciona
| @cloudflare/worker-bundler
|
Automatización web | Explorar, navegar, rellenar formularios | Browser Run |
Acceso total al sistema operativo | git, compiladores, ejecutores de tests | Sandbox |
Ejecución programada | Proactivo, no solo reactivo | DO Alarmas + Fibras |
Transmisión en tiempo real | Token por token a cualquier cliente | WebSockets |
Herramientas externas | Conectar a cualquier servidor de herramientas | MCP |
Coordinación de agentes | RPC tipificada entre agentes | Subagentes (Facets) |
Acceso al modelo | Conectar a un LLM para potenciar el agente | AI Gateway + Workers AI (o trae tu propio modelo) |
Cada uno de estos es un bloque de construcción. Juntos, forman algo nuevo: una plataforma en la que cualquiera puede crear, implementar y ejecutar agentes de IA con la misma capacidad que los que se ejecutan hoy en día en tu máquina local, pero sin servidor, duradero y seguro por construcción.
Ahora que has visto las primitivas, esto es lo que sucede cuando las conectas.
Think es un arnés predefinido que maneja el ciclo de vida completo del chat: bucle de agente, persistencia de mensajes, transmisión, ejecución de herramientas, reanudación de la transmisión y extensiones. Te enfocas en lo que hace que tu agente sea único.
La subclase mínima se ve así:
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
export class MyAgent extends Think<Env> {
getModel() {
return createWorkersAI({ binding: this.env.AI })(
"@cf/moonshotai/kimi-k2.5"
);
}
}
Eso es efectivamente todo lo que se necesita para tener un agente de chat en funcionamiento con transmisión, persistencia, interrupción/cancelación, manejo de errores, transmisiones reanudables y un sistema de archivos de espacio de trabajo integrado. Implementa con npx wrangler deploy.
Think toma las decisiones por ti. Cuando necesites más control, puedes anular los que te interesan:
Anulación | Propósito |
getModel()
| Devuelve el modelo de lenguaje que se va a utilizar. |
getSystemPrompt()
| Aviso del sistema. |
getTools()
| ToolSet compatible con el SDK de IA para el bucle agéntico.
|
maxSteps
| Número máximo de rondas de llamada de herramientas por turno. |
configureSession()
| Bloques de contexto, compactación, búsqueda, capacidades. |
De forma interna, Think ejecuta el bucle agéntico completo en cada turno: ensambla el contexto (instrucciones base + descripciones de herramientas + habilidades + memoria + historial de conversaciones), llama a streamText, ejecuta llamadas a herramientas (con truncamiento de salida para evitar la explosión del contexto), agrega resultados, se repite hasta que el modelo finaliza o se alcanza el límite de pasos. Todos los mensajes se conservan después de cada turno.
Enlaces del ciclo de vida
Think te ofrece puntos de conexión en cada etapa del turno de chat, sin necesidad de que seas el propietario de toda la canalización:
beforeTurn()
→ streamText()
→ beforeToolCall()
→ afterToolCall()
→ onStepFinish()
→ onChatResponse()
Cambia a un modelo de menor costo para los turnos de seguimiento, limita las herramientas que puede usar y pasa el contexto del lado del cliente en cada turno. También registra cada llamada de herramienta a Analytics y activa automáticamente un turno de seguimiento más después de que se complete el modelo, todo sin reemplazar onChatMessage.
Memoria continua y conversaciones largas
Think se basa en la API de Sesiones como su capa de almacenamiento, lo que te ofrece mensajes con estructura de árbol con bifurcación integrada.
Además, agrega memoria persistente a través de bloques de contexto. Estas son secciones estructuradas del indicador del sistema que el modelo puede leer y actualizar con el tiempo, y persisten durante la hibernación.El modelo ve "MEMORIA (Hechos importantes, usa set_context para actualizar) [42 %, 462/1100 tokens]" y puede recordar cosas de manera proactiva.
configureSession(session: Session) {
return session
.withContext("soul", {
provider: { get: async () => "You are a helpful coding assistant." }
})
.withContext("memory", {
description: "Important facts learned during conversation.",
maxTokens: 2000
})
.withCachedPrompt();
}
Las sesiones son flexibles. Puedes ejecutar varias conversaciones por agente y dividirlas para intentar una dirección diferente sin perder la original.
A medida que crece el contexto, Think maneja los límites con una compactación no destructiva. Los mensajes más antiguos se resumen en lugar de eliminarse, mientras que el historial completo permanece almacenado en SQLite.
La búsqueda también está integrada. Con FTS5, puedes consultar el historial de conversaciones dentro de una sesión o en todas las sesiones. El agente también puede buscar en su pasado utilizando la herramienta search_context.
La escalera de ejecución completa, integrada
Think integra todo el flujo de ejecución en un único retorno de getTools():
import { Think } from "@cloudflare/think";
import { createWorkspaceTools } from "@cloudflare/think/tools/workspace";
import { createExecuteTool } from "@cloudflare/think/tools/execute";
import { createBrowserTools } from "@cloudflare/think/tools/browser";
import { createSandboxTools } from "@cloudflare/think/tools/sandbox";
import { createExtensionTools } from "@cloudflare/think/tools/extensions";
export class MyAgent extends Think<Env> {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getTools() {
return {
execute: createExecuteTool({
tools: createWorkspaceTools(this.workspace),
loader: this.env.LOADER
}),
...createBrowserTools(this.env.BROWSER),
...createSandboxTools(this.env.SANDBOX), // configured per-agent: toolchains, repos, snapshots
...createExtensionTools({ manager: this.extensionManager! }),
...this.extensionManager!.getTools()
};
}
}
Extensiones de creación propia
Think lleva la ejecución de código un paso más allá. Un agente puede escribir sus propias extensiones: programas TypeScript que se ejecutan en Dynamic Workers, declarando permisos para el acceso a la red y las operaciones del espacio de trabajo.
{
"name": "github",
"description": "GitHub integration: PRs, issues, repos",
"tools": ["create_pr", "list_issues", "review_pr"],
"permissions": {
"network": ["api.github.com"],
"workspace": "read-write"
}
}
El ExtensionManager de Think agrupa la extensión (opcionalmente con dependencias de npm a través de @cloudflare/worker-bundler), la carga en un Dynamic Worker y registra las nuevas herramientas. La extensión permanece en el almacenamiento DO y sobrevive a la hibernación. La próxima vez que el usuario pregunte sobre las solicitudes de extracción, el agente tiene una herramienta github_create_pr que no existía hace 30 segundos.
Este es el tipo de ciclo de automejora que hace que los agentes sean realmente más útiles con el tiempo. No a través de ajustes o RLHF, sino a través del código. El agente puede escribir nuevas capacidades por sí mismo, todo en TypeScript en un entorno aislado, auditable y revocable.
Think también funciona como un subagente, llamado a través de chat() sobre RPC desde uno principal, con eventos de transmisión mediante una llamada de retorno:
const researcher = await this.subAgent(ResearchSession, "research");
const result = await researcher.chat(`Research this: ${task}`, streamRelay);
Cada subagente tiene su propio árbol de conversación, memoria, herramientas y modelo. El principal no necesita conocer los detalles.
Project Think es experimental. La superficie de la API es estable, pero seguirá evolucionando en los próximos días y semanas. Ya lo estamos utilizando internamente para crear nuestra propia infraestructura de agentes en segundo plano, y lo compartimos de forma anticipada para que puedas crear con nosotros.
npm install @cloudflare/think agents ai @cloudflare/shell zod workers-ai-provider
// src/server.ts
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";
export class MyAgent extends Think<Env> {
getModel() {
return createWorkersAI({ binding: this.env.AI })(
"@cf/moonshotai/kimi-k2.5"
);
}
}
export default {
async fetch(request: Request, env: Env) {
return (
(await routeAgentRequest(request, env)) ||
new Response("Not found", { status: 404 })
);
}
} satisfies ExportedHandler<Env>;
// src/client.tsx
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
function Chat() {
const agent = useAgent({ agent: "MyAgent" });
const { messages, sendMessage, status } = useAgentChat({ agent });
// Render your chat UI
}
Think utiliza el mismo protocolo WebSocket que @cloudflare/ai-chat, por lo que los componentes de la interfaz de usuario existentes funcionan sin problemas. Si has desarrollado sobre AIChatAgent, tu código de cliente no cambia.
Vemos tres olas de los agentes de IA:
La primera ola fueron los bots de chat. No poseían estado, eran reactivas y frágiles. Cada conversación empezaba desde cero, sin memoria, sin herramientas y sin capacidad de acción. Esto los hizo útiles para responder preguntas, pero los limitó a eso.
La segunda ola fueron los agentes de codificación. Se trata de herramientas con estado, que usan otras herramientas y son mucho más capaces, como Pi, Claude Code, OpenClaw y Codex. Estos agentes pueden leer bases de código, escribir código, ejecutarlo e iterar. Estos demostraron que un LLM con las herramientas adecuadas es una máquina de propósito general, pero se ejecutan en tu computadora portátil, para un usuario, sin garantías de durabilidad.
Ahora estamos entrando en la tercera ola: los agentes como infraestructura. Durable, distribuido, estructuralmente seguro y sin servidor. Se trata de agentes que se ejecutan en Internet, sobreviven a los fallos, no cuestan nada cuando están inactivos y aplican la seguridad a través de la arquitectura en lugar del comportamiento. Agentes que cualquier desarrollador puede crear e implementar para cualquier número de usuarios.
Esta es la dirección por la que apostamos.
El SDK de agentes ya está impulsando miles de agentes de producción. Con Project Think y las primitivas que introduce, estamos agregando las piezas que faltaban para que esos agentes sean mucho más capaces: espacios de trabajo continuos, ejecución de código en espacios seguros, tareas de larga duración, seguridad estructural, coordinación de subagentes y extensiones de creación propia.
Ya está disponible en versión preliminar. Estamos desarrollando juntos, y nos encantaría ver lo que tú (y tu agente de codificación) crean con él.
Think forma parte del SDK de agentes de Cloudflare, disponible como @cloudflare/think. Las funciones descritas en esta publicación están en versión preliminar. Las API pueden cambiar a medida que incorporamos los comentarios. Consulta la documentación y el ejemplo para iniciar.