I added an AI helper to my JSON mock-API tool — the hybrid design, and a Workers AI gotcha TempTools, a suite of free web tools that expire and delete themselves, added an AI helper to its Temp API tool that generates JSON schemas, samples, and explanations. The AI is never allowed to touch correctness—repair and formatting are handled deterministically by the jsonrepair library. A Cloudflare Workers AI gotcha caused two of three AI features to fail because the model returned parsed JSON objects instead of strings, breaking the `.trim()` call. I run TempTools https://temptools.webcli.jp — a small suite of free, no-signup web tools that expire and delete themselves. The one I use most is Temp API : paste JSON or CSV, get a live mock endpoint in seconds. I just added an AI helper to it, and the design turned out more interesting than "call an LLM." The rule I set for myself was: AI is never allowed to touch correctness. Here's how that shook out — plus a Cloudflare Workers AI gotcha that broke two of the three features while the third worked fine. Three buttons on the Temp API editor: Here's the thing I didn't want: an AI silently rewriting my JSON while pretending to "format" it. If you paste {"id": 42} and the tool hands back {"id": 43} , that's not a fix — that's a bug you'll chase for an hour. So repair and formatting are 100% deterministic . No AI. I use jsonrepair https://www.npmjs.com/package/jsonrepair : export function formatOrRepair input: string { try { return { ok: true, formatted: JSON.stringify JSON.parse input , null, 2 , repaired: false }; } catch { / not valid — try to repair / } try { const repaired = jsonrepair input ; return { ok: true, formatted: JSON.stringify JSON.parse repaired , null, 2 , repaired: true }; } catch { return { ok: false }; } } The AI is only used for things where being "approximately right" is fine and there's no source of truth to corrupt: That split matters for the copy too. It would be tempting to market this as "AI fixes your JSON " — but that's not true, and someone will call it out. The UI says the repair runs locally and reserves "AI" for the schema/sample/explanation. Honest and it dodges a whole class of complaints. The generation runs on Workers AI with an ai binding — no external API keys, it just runs on the edge: js export const AI MODEL = "@cf/qwen/qwen2.5-coder-32b-instruct"; async function runText ai, messages, maxTokens { const out = await ai.run AI MODEL, { messages, max tokens: maxTokens, temperature: 0.2 } ; return out.response.trim ; // ← this line is a trap. more below. } generateSchema and generateSample are just runText with a system prompt that says "output ONLY raw JSON, no markdown fences," and then I strip any stray fences/prose defensively before parsing. response isn't always a string Here's the bug that had me confused for a while. In production: Same model. Same runText . Same binding. So why did one of three AI calls work and two fail? I temporarily surfaced the real error in the response and got this: intermediate value .response ?? "" .trim is not a function out.response wasn't a string — so .trim didn't exist on it. The pattern clicked once I saw which calls failed. The explanation prompt returns prose , so response is a string. The schema and sample prompts return JSON — and when the model's output is JSON, Workers AI can hand you response as an already-parsed object , not a string. Calling .trim on an object throws. The fix is boring but worth knowing: don't assume response is a string. js async function runText ai, messages, maxTokens { const out = await ai.run AI MODEL, { messages, max tokens: maxTokens, temperature: 0.2 } ; const r = out as { response?: unknown } .response; const text = typeof r === "string" ? r : r == null ? "" : JSON.stringify r ; return text.trim ; } If response is a string, use it. If it's an object parsed JSON , JSON.stringify it back — which is exactly what I want to hand to the schema/sample path anyway. null / undefined becomes an empty string instead of crashing. Two debugging lessons I keep re-learning: catch → 502 hides the answer.Because repair/formatting never calls the model, the common case paste valid-ish JSON, format it costs zero AI. The model only runs when you ask for an explanation, schema, or sample. On top of that, AI calls are rate-limited per IP with a tiny rolling log table same trick I use for uploads , and the input is size-capped before it ever reaches the model. It all stays comfortably inside the Cloudflare free tier. It's live at temptools.webcli.jp/tools/temp-api — paste some rough JSON and hit the AI buttons. No signup, and the endpoint you create expires on its own. If you're building on Workers AI, keep that response -type gotcha in your back pocket. And if you find a rough edge in Temp API, I'd genuinely love to hear it. 🛠️