@cognition-ai/cloudflare-agents puts a Devin cloud session behind a
Cloudflare Agents AIChatAgent, so useAgentChat
drives Devin the way it drives a model. Each chat is a Durable Object that owns one Devin session:
the API key stays in the Worker, the transcript persists in the object’s SQLite storage, and the
session keeps working in Devin’s cloud while the Durable Object hibernates.
It is built on @cognition-ai/ai-sdk, which does the event-to-UI-message
mapping. The Cloudflare Agents chat example is a complete app on
top of it.
Setup
The
@cognition-ai packages are in beta. Every release is a 0.0.1-beta.N prerelease on the
beta dist-tag (currently 0.0.1-beta.7), so the @beta suffix is required: a bare
npm install @cognition-ai/sdk fails on purpose. Pin the exact version in your lockfile, and keep
every @cognition-ai package you use (sdk, ai-sdk, cloudflare-agents, harness-devin) on
the same version; they release together. Each published version is stable, but the API can
change between beta bumps; see the changelog for what moved.Server
The whole agent is one class and a route:src/server.ts
wrangler.jsonc
DevinChatAgent reads DEVIN_API_KEY, and optionally DEVIN_ORG_ID and DEVIN_BASE_URL, from the
Worker’s bindings. Override the hooks for anything else, such as per-user keys or scoping new
sessions to repositories:
Client
agent.state holds the session id and URL, status, activity, plan and pull requests, and updates
live while a turn streams. Messages carry text, reasoning, dynamic-tool parts whose input is
the SDK’s ToolCallDetail, and
data-devin-plan / data-devin-pull-request parts; see AI SDK UI for
the full mapping.
What the agent does
- One turn per message. The first message creates a Devin session; later ones attach to it, including after hibernation, a deploy, or from another client. Messages sent mid-turn queue.
- Stop.
chat.stop()cancels the Devin turn. A command Devin was already running finishes in its cloud VM; its late output is dropped rather than folded into the next turn. - Permissions. Devin’s permission requests arrive as AI SDK tool approvals. Answer them with
chat.addToolApprovalResponse({ id, approved }), and the same turn resumes. Approving picks allow-once; denying picks reject-once. - Start over.
agent.stub.startOver()detaches from the session and stops the turn, so the next message starts a new session. Clear the transcript withchat.clearHistory(). The old session keeps running in the cloud. - Continue an existing session.
agent.stub.importSession(id)rebuilds the transcript from the session’s replay and attaches future turns to it — the way to pick up a session started in the Devin app. It throws on a chat that already has a session or messages.parseSessionId(input)accepts a session id or a Devin web app URL. - Recovery. If the Durable Object restarts mid-turn, what already streamed is kept and the prompt is not sent again: Devin already has it.
- Late events. Events from a turn the chat moved on from (stopped, started over) never touch the new session’s state.
LocalDevin needs Node.js or Bun.
Building your own agent
For a different agent shape,connectDevin(env) opens a connection from the bindings, and
reduceDevinChatState(state, event) projects session events onto DevinChatState. Combine them
with toUIMessageStream, toUIMessages and ToolApprovals from
@cognition-ai/ai-sdk.
