Which step breaks first on a local model: choosing the tool, filling the arguments, or finishing a long task?

Casey Holt

Casey Holt

October 7, 2026

Which step breaks first on a local model: choosing the tool, filling the arguments, or finishing a long task?

Filling the arguments breaks first. On a short tool list with distinct names, a local model usually picks the right tool and then puts the wrong value in a field, swaps two fields, or drops one the schema marked required. You can see that on the first or second call, before the task is long enough to blame fatigue. Choosing the tool breaks first only when the list is crowded and two names could both apply. Finishing a long task is the failure that makes you give up on the local model, but it is not the first break. By then the arguments have already been wrong at least once, and the model has started treating a bad edit as progress.

If you only watch the last message, you will misname the bug. The last message says the rename is done. The first bad argument was three calls earlier, and everything after it was the model defending that call.

What the three steps actually are

Choosing the tool is the name. You handed the model a list: read a file, search the repo, edit a file, run a test. It has to emit one of those names, not a synonym it prefers and not a paragraph about what it would do.

Filling the arguments is everything inside that call. Path, old string, new string, line range, URL, whether to create the file if it is missing. The name can be perfect and the call can still be useless, or worse, destructive in a small way: it edits the wrong occurrence because the old string was too short.

Finishing a long task is the part after the first success. The original request is still only half done. The model has to look at the tool result, decide the next call, and stop when the request is actually finished rather than when it has produced a confident sentence. This is a memory and a discipline problem. It shows up after the schema problem, not before it.

I separate them because people fix the wrong one. They add more tools, or they switch to a larger local model, when the trace already shows the right tool name and a path that does not exist.

The rename that failed in the second field

The job was small on purpose. A config key, invoice_prefix, had to become invoice_series in one service. Three tools, names a person could not mix up: search, read_file, edit_file. No browser. The model was a mid-size local instruct model with a tool template the runtime already parsed. I was not testing whether it could browse. I was testing which step died first.

Call one was search. The name was right. The query argument was invoice_prefix. Good. The tool returned four hits: the key in a YAML file, the same string in a comment above it, a test fixture, and a docs sentence.

Call two was edit_file. The name was right again. The path was the YAML file, also right. The old_string argument was the comment line, not the key. The new_string rewrote the comment and left invoice_prefix in place one line below. The tool reported success, because the comment really did contain that substring and the edit really did apply.

That is an argument failure, and it happened before the task was long. The model had chosen correctly twice. The field that mattered was the one that selected which bytes to change. It selected a nearby lookalike.

Call three is where people start saying “it can’t finish long tasks.” The model read the tool’s success, did not read the file again, and wrote that the rename was complete. I had asked for the key, the fixture, and a check that tests still mention the new name. It had touched a comment. The long-task failure is real. It is downstream. If the second call had carried the key and not the comment, the later sloppiness would be the story. It did not get that far with a correct edit.

A clipboard form with empty fields next to a laptop keyboard

Why arguments fail before the name does

Tool names are few and they sit in the prompt as a list. A local model that has seen a tool-calling format can copy a name. The names are short tokens. edit_file does not require the model to know your repo.

Arguments are your repo. The path is a string the model has to copy from a search result without dropping a directory. The old string has to be long enough to be unique and short enough to match exactly, including spaces. A required boolean has to be a boolean, not the word “yes.” Local models are decent at the shape of JSON and bad at the exact bytes, especially when the tool result and the original request are both in context and the right substring appears twice.

I see the same pattern on URLs. The model chooses browse or http_get correctly, then appends a heading slug it half-remembered, or it percent-encodes a character that was already encoded. The tool returns a 404. If you only score “did it try to browse,” the step looks fine. The job failed in the argument.

Numbers are worse than strings. A line range, a timeout in seconds, a limit on search results. Small models substitute a round number from the prompt example. The schema said the example was an example. The model used it as the value. The tool runs. You get the first fifty lines of the wrong file region and a summary that sounds like the whole file.

When choice does break first

Choice breaks first when two tools can honestly answer the same verb in the request. “Get the page” with both http_get and browser_navigate on the list is a choice test, not an argument test. A local model will pick the one that looks like curl, because the word “get” is right there, and it will never see the button the browser tool was for. The arguments to http_get can be perfect. The step that broke was the name.

Choice also breaks first when the list is long enough that the names overlap: search, grep, find, glob, codebase_search. I have watched a local model call three of them in a row with the same query string, burn the context on duplicate hits, and only then try to edit. Each call was well-formed. The selection was noise. On that list, you cannot even grade the arguments fairly, because the model never settled on the tool that needed a careful path.

If your list is under about five tools and the names describe different actions, do not start by blaming selection. Read the arguments. If your list is a catalog, selection is the first break, and shrinking the list is the fix, not a bigger prompt that repeats all fifteen names.

The long task fails later, and it fails differently

A long task is a chain: result, next call, result, next call, stop. Local models lose the original request in the middle of that chain even when early arguments were good. I have seen a clean first edit followed by a second edit that “helps” by renaming a different key the search also returned. The model is no longer executing the request. It is continuing the activity of editing.

The stop condition is the part no schema can fully hold. The model decides it is done. Local models decide that early, usually right after a tool returns success, because success feels like the end of a turn. Frontier models do this too. They do it after more of the list is actually finished, and they are more willing to call read_file again when you say the key is still there.

So if your trace shows a wrong field on call two, you do not have a long-task problem yet. You have an argument problem that the later calls are decorating. Fix the argument, rerun, and then see whether it can hold the list. People who skip that rerun buy a larger model to cure a string that was two characters short of unique.

A long hallway of identical doors with one door slightly open

How to tell which step you are looking at

Read the raw call, not the assistant’s recap. Three checks, in order:

  • Is the tool name one you provided, and is it the action the request needed? If the name is wrong or missing, choice broke, and the arguments are not evidence yet.
  • If the name is right, do the fields match the schema and the bytes in the tool result? A successful tool response is not a pass. Success means the runtime applied what it was given. Check what it was given.
  • Only if the early calls are right: did a later call drop an item from the original list, edit something the request did not name, or stop while a hit was still untouched? That is the long task.

Keep a job you already know the answer to, and run it whenever you change model or tool list. My check is still that rename, plus a second job with two tools that both “get” a page, so I can see choice break on purpose. If the rename’s old_string is wrong, I do not bother timing a twenty-step browse. The model has not earned the long task.

What I change, depending on the step

When arguments break first, I shorten the fields the model has to invent. The search tool returns a path. The edit tool receives that path from the harness when there is only one hit, instead of asking the model to copy it. The old string has to be the full line, and the tool rejects a match that appears more than once. I would rather have an error on call two than a successful edit of a comment. Errors are visible. Silent comment edits look like a finished task.

When choice breaks first, I delete tools until the remaining names cannot be confused. Search or grep, not both. A browser or an HTTP get, not both, unless the request truly needs a click. A local model will not develop judgment because you added a paragraph explaining the difference. It will copy the name that sat closest to the verb.

When the long task is the thing that actually breaks, and the early calls are clean, then a larger model or a frontier model for that chain is the honest fix. Splitting the job into single edits you confirm one at a time also works, and it keeps the local model. What does not work is telling the local model “be careful and finish every item.” It already thought it had.

The order to remember

On the tool list you should be using with a local model — short, names that do not overlap — the arguments go bad first. Tool choice is the early failure only after you have made the list ambiguous. The long task is the reason a local agent feels unreliable over a real request, and it is the second or third break, not the first one in the trace.

Grade the trace in that order before you change models. A wrong string in the second field is a harness and a schema problem you can often fix this afternoon. A model that edits the right bytes and then walks off the original list is a different decision: stay local and shorten the job, or stop pretending the local model is the one that should finish it.

More articles for you