cd /news/ai-tools/deprecated-accessor-footgun-in-ai-sd… · home topics ai-tools article
[ARTICLE · art-51066] src=lightningjar.com ↗ pub= topic=ai-tools verified=true sentiment=↓ negative

Deprecated Accessor Footgun in AI SDK v7

A bug in the AI SDK v7 migration caused small language models to fail at multi-turn tool calling by silently truncating conversation history. The deprecated `result.response.messages` property, which previously returned all messages, now returns only the final step's text, breaking tool-calling workflows. The issue affected models like Gemini 3.5 Flash and Claude Haiku 4.5, with failure rates up to 96%, while larger models were unaffected.

read9 min views1 publishedJul 8, 2026

*Companion note:*This piece follows We Benchmarked It and HTML as a Native Data Format for LLMs, but this one isn't about markup. It's about a single line of conversation plumbing that quietly decides whether small models can do multi-turn tool calling at all.

Here's a transcript from our benchmark. The model has just created a node with a tool call; the system assigned it id m1

and told the model so. One turn later, we ask for the simplest edit imaginable:

User:Set the "requireBleed" attribute to true on the node with id "m1" (the widget-slot you created in the previous step). Make the changes with the tools, then reply DONE.

Assistant:DONE

No tool call. No edit. Just: DONE. A cheerful, confident lie.

We had 114 of these (the count from a fresh, fully instrumented re-run of the broken protocol with transcripts captured; the original run had 110, run-to-run variance, same disease). Every one of the 114 was transcript-classified the same way: correct instruction in, zero tool calls out, "DONE." The smaller the model, the worse it got: gemini-3.5-flash failed 96% of these follow-ups, claude-haiku-4.5 failed 71%, while gpt-5.4 and claude-sonnet-4.5 sailed through. We published the finding with a number on it: whole-tree rewrite beat granular tool calling by 33 points on multi-turn edits. We had a tidy story about small models and multi-turn fragility.

The story was wrong. Not the data: the data was real, reproducible, temperature-zero real. The interpretation was wrong, and the way we found out is the most useful thing this benchmark ever produced.

Results too weird to trust #

Because the failure mode was so strange (models that execute an instruction flawlessly in turn one, then ignore the identical instruction shape in turn three), we pre-registered a follow-up study to isolate the mechanism. Conversation depth. Mitigation prompts. A fresh-context control. Six models, 2,160 cells.

The ablations came back weird. Depth didn't behave: some models got better with more intervening turns, some worse, no coherent curve. A "restate the instruction before acting" mitigation (the kind of prompt hygiene everyone recommends) made gpt-5.4 collapse from 100% to 7.5%. Meanwhile a fresh conversation fixed every model, instantly, universally.

Results that incoherent usually mean you're not measuring what you think you're measuring. So I went to read the raw conversation histories we were sending, not the ones I assumed we were sending.

The bug #

Our harness used the AI SDK (v7). After each tool-calling turn, it appended the result to the running conversation like this:

messages.push(...result.response.messages); // looks right. isn't.

Here's the thing: in a multi-step tool run, result.response.messages

contains only the final step's assistant text. The tool calls the model made, and the tool results it received, live one level down, per step. What you actually want is:

messages.push(...result.responseMessages); // the idiomatic v7 accessor

// equivalent, built from the per-step data:
messages.push(...result.steps.flatMap((s) => s.response.messages));

And what makes this a migration trap rather than a plain bug: result.response.messages

was the documented v5 pattern for exactly this purpose. v7 kept the property, changed its meaning to final-step-only, and moved the accumulated history to a new top-level accessor, result.responseMessages. It is documented in the migration guide, but silent at the call site. No compile error. No runtime signal. (The property does carry a

@deprecated

JSDoc note: a strikethrough for humans in editors, invisible to CI, to generated code, and to anyone not hovering.) Code written against v5 still typechecks, still runs, and quietly means something else. Crueler still: the pattern v7 demoted is the very one the 4.0 migration guidetold everyone to adopt: 4.0 deprecated

responseMessages

in favor of response.messages

, and v7 moved the accumulated history back to responseMessages

. The name has switched meanings twice. We filed this upstream as vercel/ai#16840; the maintainers triaged it as working-as-documented, an enhancement request for guardrails and migration tooling, not a bug. Under the project's definitions, that's a defensible call, and this post isn't an indictment of one SDK. It's about what this

classof change (a semantic swap behind a stable, typechecking name) does when it meets agent conversation plumbing.

One line. But with the first version, every multi-turn conversation we ran had a hole in it: the model's own tool activity was erased from its history. From the model's point of view, the past looked like this: user asked for an edit; I replied "DONE." No insertNode call. No tool result with the new id. Just a user request and a one-word answer that apparently satisfied everyone.

Read that transcript again with the model's eyes and the behavior stops being mysterious. It isn't ignoring your instruction. It's continuing the only pattern its context contains.

The controlled proof #

Because the follow-up study was already built, re-running it with corrected histories gave us something rare: a perfect A/B of one plumbing decision, 2,160 cells per protocol, same tasks, same models, same prompts.

With the model's tool calls hidden from history, follow-up execution ranged from 5% to 100% depending on model and configuration. With correct history: 100%. Every model. Every arm. Every depth. 2,160 for 2,160.

On the original benchmark's multi-turn tasks (tools conditions, pooled):

Model Broken history Corrected history
gemini-3.5-flash 3.8% (3/80) 71.2% (57/80)
claude-haiku-4.5 28.8% (23/80) 98.8% (79/80)
claude-sonnet-4.5 96.2% (77/80) 100% (80/80)
gpt-5.4 96.2% (77/80) 100% (80/80)

(Reference-family tasks, both tools conditions pooled, parity prompts, n = 80 per model per protocol; full tables and slice definition in results/analysis-permodel-reference.txt.)

Multi-turn reference-edit success by model, tools conditions pooled: the model's own tool calls hidden from history versus corrected history.

Same tasks. Same models. Same prompts. The only thing that changed is whether the conversation history contained the model's own tool calls. (Gemini's residual corrected-history failures are all phase-one accuracy, fumbling the initial insert, not follow-up dropout. The dropout class went to zero in every model.)

Why you probably wouldn't catch it #

Look at the bottom two rows of that table. The frontier models barely notice the defect. They act on the current instruction no matter how odd the history looks, which sounds like a virtue, and is, right up until it becomes camouflage.

Because here's the standard lifecycle of an agent feature: you build it against a frontier model, your evals pass, you ship. Six months later someone points out the assistant endpoint would be 20× cheaper on a small model, and the evals (run on the frontier model) still pass. The defect has been sitting in your history construction the whole time, invisible, waiting for the model swap to detonate it. The failure it produces doesn't throw, doesn't log, and doesn't look like an error. It looks like a cheerful "DONE."

And one more trap from our ablations: prompt mitigations interact with the broken history in model-specific, catastrophic ways: that restate-first instruction took gpt-5.4 from 100% to 7.5% under the broken history and was harmless under the correct one. If you've ever seen a prompt tweak inexplicably nuke one model's tool use, audit your history before you blame the prompt.

The five-minute audit #

Dump the exact message array you send on turn N+1 of a tool-using conversation, not what your abstraction claims, the actual array. Look fortool-call

andtool-result

parts from turn N. If your assistant turns are all bare text, you have the bug.Check your persistence layer. The SDK-level fix isresult.responseMessages

(the official accumulated-history accessor) or the equivalentsteps.flatMap(s => s.response.messages)

, but the same hole opens one layer up: if your conversation store saves only the assistant's visible text (very common: that's what the user sees), every rebuilt history is tool-less no matter what the SDK returned.Add one regression test: run a two-turn tool conversation; assert the rebuilt history for turn two contains at least one tool-call part and one tool-result part. It's the cheapest insurance in agent engineering.Re-run your evals on your cheapest model, not your best one. Small models are your canary for context defects. If haiku-class models suddenly can't follow up, don't conclude they're bad at tools: we did, in public, with confidence intervals.

There's also a structural way out: interfaces where the model's work product is its visible reply (whole-artifact rewrite, patch formats) are immune to this entire failure class. There's no hidden tool channel to lose. In our corrected benchmark, tools and rewrite perform within a couple of points of each other; the honest argument for whole-artifact designs is no longer accuracy, it's that they have strictly less plumbing that can silently fail.

What it cost us #

We'd published numbers this bug manufactured: "+5.3 points for rewrite over tools," "+33 points on multi-turn edits," "tool fragility is a small-model problem." Corrected: tools and rewrite are at parity (tools actually edge ahead by 2 points); the multi-turn gap is gone; haiku's tool score jumped from 80.5% to 95% without haiku changing at all. The corrections are live in the benchmark repo and annotated in both earlier posts, with the original claims left visible: that's what pre-registration and publishing-either-way are for. The findings that survive (format-fluency parity, token economics, positional JSON Patch collapsing on big trees, id-anchored patches matching rewrite at the lowest cost) survive because the protocols they ran under never touched the broken code path.

One last, slightly uncomfortable thought. Multi-turn tool benchmarks are everywhere right now, and every one of them constructs conversation histories in framework code that nobody's results section describes. Our +33-point phantom effect had confidence intervals, p-values, temperature 0, and 8,000 scored runs behind it. Rigor didn't save us; reading the transcripts did. If you maintain a multi-turn eval (or trust one), it's worth an afternoon to go look at what your models actually see.

*Update (July 2026):*A later session study (Study K, 140 twelve-edit sessions) confirmed the diagnosis from the opposite direction: with its own edit history fully visible, gemini-3.5-flash tracked twelve turns of its own patches at 96.3% in the final session third, barely drifting, while the frontier model leaned on a stale mental picture of a tree shown only once and fell to 83.8%. Hidden history was the disease; visibility is the cure, at every tier. Details: Your Agent's Session Is Drifting.

── more in #ai-tools 4 stories · sorted by recency
── more on @ai sdk 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/deprecated-accessor-…] indexed:0 read:9min 2026-07-08 ·