Describe the bug
examples/think cannot complete a single chat turn under wrangler dev. Every model call fails with an opaque internal error; reference = <id>, surfaced to the terminal client as:
Error: internal error; reference = kl1uqro0lemqfdd6nga1j8t7
at async Object.fetch (…/miniflare/dist/src/workers/core/entry.worker.js:4723:22)
The cause is the calling context, not the request: the remote Workers AI binding does not work from inside a Durable Object under wrangler dev. The example's model call lives in the Assistant DO (examples/think/src/agent.ts:125-127):
override getModel() {
return createWorkersAI({ binding: this.env.AI })(MODEL_ID);
}
and examples/think/wrangler.jsonc:13 declares that binding as remote:
Measured from inside that same DO, in the same turn:
| call |
result |
fetch("https://example.com/") |
200 |
fetch("https://api.cloudflare.com/client/v4") |
404 (i.e. reached the server) |
env.AI.run(…) |
internal error; reference = … |
So general outbound HTTP from the DO is fine; only the AI binding fails there. The identical env.AI.run call succeeds from a plain Worker fetch handler in the same project, same account, same model.
I bisected the request to rule out payload causes. Every one of these still failed from the DO, while all of them succeeded from a plain Worker:
- with tools and without tools (
tools: undefined)
stream: true and stream: false
- 1, 3, 6, 9 tools, and the example's real tool schemas
tool_choice: "auto" present and absent
- the real 4-message history, and a single
{role:"user",content:"Say OK."}
- a second model (
@cf/qwen/qwen2.5-coder-32b-instruct)
The last two are the decisive ones: a no-tools, one-message, different-model request still fails from the DO. Note Assistant is both the agent DO and the container class (examples/think/wrangler.jsonc:17, and the withWorkspaceContainer mixin at examples/think/src/agent.ts:65), so a container-related egress path is a plausible suspect, but I did not confirm that — plain fetch from the same DO is unaffected.
This may well be a wrangler/miniflare limitation rather than a bug in this repo. Filing it here because the effect is that the example is unusable locally as shipped, and the workaround belongs with the example either way.
Expected behavior
npm run dev + npm run chat in examples/think completes a chat turn, as examples/think/README.md describes. Failing that, the example documents the limitation and uses a code path that works locally.
Steps to reproduce
npm install at the repo root; wrangler login.
cd examples/think && npx wrangler dev (Linux or WSL — containers are unsupported on Windows).
npm run chat, then send any message.
- Observed:
Error: internal error; reference = …. Expected: a reply.
To isolate it from the agent entirely, point a plain Worker at the same binding:
export default {
async fetch(request, env) {
const r = await env.AI.run("@cf/meta/llama-3.3-70b-instruct-fp8-fast", {
messages: [{ role: "user", content: "Say OK." }], max_tokens: 16,
});
return new Response(JSON.stringify(r));
},
};
npx wrangler dev on that returns a normal completion. The same call from the Assistant DO fails.
Separate blocker worth noting, since it is hit first and masks this one: MODEL_ID at examples/think/src/agent.ts:52 is @cf/zai-org/glm-5.2, which returns AiError 5035: This model requires a Workers Paid plan. On a free account the example fails there before reaching the DO problem. @cf/meta/llama-3.3-70b-instruct-fp8-fast, @cf/qwen/qwen2.5-coder-32b-instruct, and @cf/mistralai/mistral-small-3.1-24b-instruct all work on the free plan and support tool calling; @cf/meta/llama-3.1-8b-instruct is deprecated as of 2026-05-30.
Proposed fix
workers-ai-provider supports a credentials mode that goes over plain fetch instead of the binding, and plain fetch works from the DO. Falling back to it only when credentials are present keeps the binding for deployed workers, where it is fine:
override getModel() {
const accountId = this.env.CF_ACCOUNT_ID;
const apiKey = this.env.CF_AI_TOKEN;
if (accountId && apiKey) {
return createWorkersAI({ accountId, apiKey })(MODEL_ID);
}
return createWorkersAI({ binding: this.env.AI })(MODEL_ID);
}
With CF_ACCOUNT_ID and CF_AI_TOKEN (an API token scoped to Account → Workers AI → Read) in examples/think/.dev.vars, the example completes chat turns locally, including container-backend exec. That is a workaround rather than a fix — if the binding is expected to work from a DO under wrangler dev, this is really a wrangler issue and I am happy to re-file it there.
Choosing a default model that exists on the free plan would also let the example run without a paid account.
Environment
cloudflare/computer at 76d9e75 (current main)
- Ubuntu 24.04 under WSL2, Docker 29.1.3, wrangler 4.115.0, Node 22.22.1
- Workers free plan;
examples/think with both the worker-shell and container backends registered
Describe the bug
examples/thinkcannot complete a single chat turn underwrangler dev. Every model call fails with an opaqueinternal error; reference = <id>, surfaced to the terminal client as:The cause is the calling context, not the request: the remote Workers AI binding does not work from inside a Durable Object under
wrangler dev. The example's model call lives in theAssistantDO (examples/think/src/agent.ts:125-127):and
examples/think/wrangler.jsonc:13declares that binding as remote:Measured from inside that same DO, in the same turn:
fetch("https://example.com/")200fetch("https://api.cloudflare.com/client/v4")404(i.e. reached the server)env.AI.run(…)internal error; reference = …So general outbound HTTP from the DO is fine; only the AI binding fails there. The identical
env.AI.runcall succeeds from a plain Workerfetchhandler in the same project, same account, same model.I bisected the request to rule out payload causes. Every one of these still failed from the DO, while all of them succeeded from a plain Worker:
tools: undefined)stream: trueandstream: falsetool_choice: "auto"present and absent{role:"user",content:"Say OK."}@cf/qwen/qwen2.5-coder-32b-instruct)The last two are the decisive ones: a no-tools, one-message, different-model request still fails from the DO. Note
Assistantis both the agent DO and the container class (examples/think/wrangler.jsonc:17, and thewithWorkspaceContainermixin atexamples/think/src/agent.ts:65), so a container-related egress path is a plausible suspect, but I did not confirm that — plainfetchfrom the same DO is unaffected.This may well be a wrangler/miniflare limitation rather than a bug in this repo. Filing it here because the effect is that the example is unusable locally as shipped, and the workaround belongs with the example either way.
Expected behavior
npm run dev+npm run chatinexamples/thinkcompletes a chat turn, asexamples/think/README.mddescribes. Failing that, the example documents the limitation and uses a code path that works locally.Steps to reproduce
npm installat the repo root;wrangler login.cd examples/think && npx wrangler dev(Linux or WSL — containers are unsupported on Windows).npm run chat, then send any message.Error: internal error; reference = …. Expected: a reply.To isolate it from the agent entirely, point a plain Worker at the same binding:
npx wrangler devon that returns a normal completion. The same call from theAssistantDO fails.Separate blocker worth noting, since it is hit first and masks this one:
MODEL_IDatexamples/think/src/agent.ts:52is@cf/zai-org/glm-5.2, which returnsAiError 5035: This model requires a Workers Paid plan. On a free account the example fails there before reaching the DO problem.@cf/meta/llama-3.3-70b-instruct-fp8-fast,@cf/qwen/qwen2.5-coder-32b-instruct, and@cf/mistralai/mistral-small-3.1-24b-instructall work on the free plan and support tool calling;@cf/meta/llama-3.1-8b-instructis deprecated as of 2026-05-30.Proposed fix
workers-ai-providersupports a credentials mode that goes over plainfetchinstead of the binding, and plainfetchworks from the DO. Falling back to it only when credentials are present keeps the binding for deployed workers, where it is fine:With
CF_ACCOUNT_IDandCF_AI_TOKEN(an API token scoped to Account → Workers AI → Read) inexamples/think/.dev.vars, the example completes chat turns locally, including container-backendexec. That is a workaround rather than a fix — if the binding is expected to work from a DO underwrangler dev, this is really a wrangler issue and I am happy to re-file it there.Choosing a default model that exists on the free plan would also let the example run without a paid account.
Environment
cloudflare/computerat76d9e75(currentmain)examples/thinkwith both the worker-shell and container backends registered