# I added an AI helper to my JSON mock-API tool — the hybrid design, and a Workers AI gotcha

> Source: <https://dev.to/solca/i-added-an-ai-helper-to-my-json-mock-api-tool-the-hybrid-design-and-a-workers-ai-gotcha-pb9>
> Published: 2026-07-22 16:28:27+00:00

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. 🛠️
