Run your workspace
System health & diagnostics
Every workspace admin gets a self-serve diagnostic at
/app/system-health. The page is read-only — it does
not call any external API and cannot mutate state — and it surfaces
the four config gaps that account for ~90% of "the bot isn't
working" support tickets:
-
LLM provider — resolves the bound
OpenAiClient. Green when Workers AI / OpenAI / OpenRouter is configured. Red when the deterministicFakeOpenAiis in play (no real provider). -
Cloudflare creds — checks
CLOUDFLARE_ACCOUNT_ID+CLOUDFLARE_API_TOKEN. Amber when only one is present; green when both are. -
Embedding fallback — checks
OPENAI_API_KEY. Amber when missing: the install works on the happy path but the next Workers AI rate-limit will halt indexing. -
Queue worker — surfaces the queue driver,
pending count, and failed-job count. Amber when queue is
sync(fine for dev, broken for prod where SSE + crawl jobs need their own workers).
Source-level problems
Beneath the four cards is a list of every Source in
the workspace whose status is failed or stuck on
crawling, ordered by most recently updated.
IndexDocumentJob stamps the exception class name into
each row's error column, so the admin can tell a
rate-limit ([OpenAiRateLimitException]) apart from a
bad-request ([OpenAiBadRequestException]) apart from a
Cloudflare 40040 (Vectorize provisioning lag).
Cloudflare Workers AI: non-Llama models
Workers AI's /v1/chat/completions endpoint is OpenAI-
compatible in name, but model families diverge in two ways
that affect the bot:
-
Streaming shape varies. Llama 3.3 emits the
OpenAI SSE shape (
data: {"choices":[{"delta":{"content":"..."}}]}). Other families (Mistral, some Gemma builds, Qwen variants) emit either NDJSON without thedata:prefix or a CF native{"response":"..."}shape on the same endpoint.WorkersAiClient::streamChat()handles all three (since 2026-05-29) so any chat-capable Workers AI model streams tokens. -
Not every Workers AI model has a chat endpoint.
Embedding / classification / Whisper models silently return
empty bodies on
/v1/chat/completions. When the Settings → System chat probe surfaces "No content via streaming OR non-streaming", the configuredCLOUDFLARE_CHAT_MODELisn't a chat model — switch to any@cf/meta/llama-*slug or a Mistral instruct variant.
The chat probe runs streaming first; if streaming yields zero tokens it retries non-streaming. Three outcomes:
- Both work → green, surfaces the model's reply.
- Streaming empty, non-streaming worked → red, points the operator at a streaming-capable slug. The bot still works in non-streaming fallback paths, but the visitor SSE path needs a streaming-capable model to be useful.
- Both empty → red, the configured model has no OpenAI-compat chat endpoint.
Timeouts vs. network failures
When a turn fails to reach the model, the error you see (in the Playground bubble and the Settings → System probes) now distinguishes four transport failures instead of lumping them all under "check your firewall/DNS". The distinction matters: three of them are network-config problems on your server, but the most common one — a timeout — is not.
-
Timed out (slow provider). "The AI provider
accepted the request but did not respond in time…" The
connection succeeded; the model was just too slow — almost always
a large model (e.g. Llama 3.3 70B) cold-starting or under load
overrunning the per-call timeout. This is not a
firewall or DNS fault. On Cloudflare the app already
auto-switches to a second
Cloudflare model when the primary times out, so most cold
starts self-heal without anyone noticing. If you still see this,
the fallback model is timing out too — switch
CLOUDFLARE_CHAT_MODEL(and/orCLOUDFLARE_CHAT_MODEL_FALLBACK) to faster variants, or add another provider for an extra failover hop. - DNS lookup failed. "Could not resolve the AI provider's hostname…" The server can't resolve the provider domain — check the host's DNS resolver and outbound access.
- Connection refused / blocked. "Could not open a connection to the AI provider…" DNS resolved but the connection was refused or dropped — an outbound firewall or a blocked port. This is the genuine "check your firewall" case.
- Other transport error. A TLS handshake failure, empty reply, or receive failure — generic outbound-network line.
A single-provider install (the default) has no failover to mask a slow primary, so a cold-start timeout surfaces directly to whoever's in the Playground. Adding a second provider key is the durable fix; a faster model is the quick one.
Access control
Workspace owners + admins can load the page; viewers get 403. The sidebar entry under "Run your workspace" only appears for users who can see the route.