In a ReAct loop, what does the runtime do with an action before the tool runs?
answer
- the model requests, the runtime decides
- three stages before anything executes
- resolve, deserialize, validate
- never fuzzy-match an unknown tool name
- well-formed is not the same as correct
basics
~20 sThe runtime resolves the action name against its registered tool catalogue, deserializes the arguments and validates them against that tool's schema, then executes. Anything that fails resolution or validation never reaches the tool — an error is returned instead.
solid answer
~50 sBetween the model emitting an action and any real work happening there is a dispatch boundary owned by the runtime, not the model. Three things happen there. **Name resolution**: the emitted tool name is looked up in the registered catalogue, and a name that is not in it is rejected outright rather than guessed at. **Argument deserialization**: the arguments are turned from whatever the model produced into a typed structure. **Validation**: that structure is checked against the tool's declared schema — required fields present, types right, enums in range — before the function is called. Only then does the tool execute. The reason this sits in the runtime is that a language model produces plausible text, not guaranteed-valid calls; treating its output as an untrusted request that must be authorised and validated is what keeps a bad token from becoming a bad side effect.
go deeper
Be able to state that the model only emits a request and your code executes it, and name the three stages: look up the tool, parse the arguments, check them against the schema before running anything.
Explain why validation lives in the runtime rather than in each tool, what distinguishes a parse failure from a schema violation, and why an unrecognised tool name must be rejected rather than fuzzy-matched.
Show that you treat every action as an untrusted request: authorisation and tenant checks at the same boundary, structured actionable errors fed back to the loop, and dispatch-rejection rates monitored as a leading indicator of prompt or catalogue regressions.
Own the boundary as a platform contract — one dispatch path that every tool inherits validation, authorisation, logging and quota from, so that adding a tool cannot accidentally add an unguarded execution path across the fleet.
## What dispatch means A ReAct agent alternates reasoning with acting. The acting half is not a single event — it is a small pipeline the runtime executes every time the model asks for a tool. Understanding that pipeline is what separates "the model calls the tool" (wrong, and dangerously so) from "the model *requests* a call and my code decides whether it happens" (right). The model never executes anything. It emits an intent: a tool name plus a bag of arguments. Your process — the agent loop, harness, or framework — is what turns that intent into a function call, an HTTP request, or a query. Everything between those two points is dispatch, and it is entirely under your control. ## Step one: name resolution The agent has a catalogue of tools it was told about. Dispatch looks the emitted name up in that catalogue. Two outcomes matter. If the name matches, you have a handle on the implementation and, crucially, on its declared schema. If it does not match, the model has asked for a tool that does not exist — a very common failure, especially when the catalogue is large or the names are near-synonyms. The correct response is to **fail closed**: do not fuzzy-match to the nearest registered name, do not silently skip the step. Return an explicit, machine-readable error saying the name was not recognised and listing the names that are valid. Fuzzy matching is tempting and is a real source of production incidents, because "closest string" is not "what the user meant" — `delete_draft` and `delete_document` are one edit apart. ## Step two: deserialization The arguments arrive as data the runtime must interpret: a JSON object from a provider's structured tool-calling output, or a chunk of text your parser has to read in an older prompted-ReAct setup. Deserialization turns that into a typed value your language can work with. It can fail on its own — malformed JSON, a truncated object because generation hit a token limit mid-argument, an unterminated string. A deserialization failure is a distinct condition from a validation failure and is usually worth reporting as such, because the fix is different. ## Step three: schema validation Even a perfectly parsed object can be wrong. Validation checks the parsed arguments against the schema the tool declared: required fields are present, types match (a `limit` of `"50"` is not `50`), enum-valued fields hold one of the allowed values, numbers sit inside declared bounds, nested objects have their own required keys. This has to run in the runtime, before the tool body. Two weaker placements show up in real code and both are mistakes. Validating *inside* the tool means every tool re-implements the same checks and some of them forget; worse, the tool may have already done partial work before it notices. Assuming the model validates for you means trusting a probabilistic text generator with your invariants. Schema-constrained generation (where the decoder is restricted to tokens that keep the output schema-valid) makes structural violations rare, but it constrains *shape*, not *meaning*: a well-formed `{"account_id": "12345"}` can name an account the user has no right to touch. ## Authorisation belongs here too Because dispatch is the one place every call funnels through, it is also where you enforce what the model is *allowed* to do: is this tool permitted in this session, for this user, at this point in the task; does the argument reference a resource inside the caller's tenant. Schema validity and permission are different questions, and the second one is never answerable from the schema alone. ## Failing closed, usefully When any stage rejects the action, nothing runs, and the loop still needs to continue. The rejection is returned as the step's result in the same channel a successful result would use, so the agent's next reasoning step can see what went wrong. Make the message specific and actionable — which field, what was expected, what was received — because that text is effectively a prompt for the model's next attempt. A bare `"error"` gives it nothing to correct. Also log it. Rejected dispatches are one of the highest-signal metrics an agent emits: a spike in unresolved names or schema violations usually means a catalogue change, a prompt regression, or a model swap, and it shows up at the dispatch boundary long before it shows up in user-visible answers. ## What interviewers are checking That you place validation and authorisation on the runtime side of the boundary, that you fail closed rather than guessing, and that you can articulate the difference between an argument that is *well-formed* and one that is *correct*. Candidates who describe the model as "calling the API" usually have not built the boundary at all.
- Why not fuzzy-match an unrecognised tool name to the closest registered one?Because string distance is not intent. `delete_draft` and `delete_document` differ by a few characters but not in blast radius, and a silent correction hides the fact that the model is confused about the catalogue. Fail closed instead: return an error naming the valid tools, which is both safe and a better signal for the model's next attempt — and log it, because a rise in unresolved names is an early warning of a prompt or catalogue regression.
- Schema-constrained generation guarantees the arguments match the schema. Does that make runtime validation redundant?No. Constrained decoding guarantees shape, not meaning. The arguments can be structurally perfect and still name a nonexistent record, a resource in another tenant, or a value that is valid in isolation but wrong for this task. Runtime checks also cover what a JSON Schema cannot express — permissions, cross-field consistency, referential existence — so the validation step stays, it just stops catching type errors.
- Where does authorisation fit relative to schema validation?After it, and separately. Schema validation answers "is this a well-formed request for this tool"; authorisation answers "is this caller allowed to make it right now, on this resource". A schema can require an `account_id` but cannot know that the session's user has no claim to that account. Putting both at the dispatch boundary means every tool gets them, including the one someone adds next month.
saying these in an interview costs you the question
- Saying the model itself calls the API or runs the tool
- Validating arguments inside the tool body instead of before it
- Fuzzy-matching an unknown tool name to the nearest registered one
- Assuming schema-valid arguments are therefore semantically correct
- Swallowing a rejected action instead of returning an error to the loop