How to Implement Tool Parameter Fidelity to Prevent Silent Input Transformation Bugs in Agents
Enforce strict JSON Schema contracts for every tool, validate all required arguments in a centralized dispatch method, and isolate tool sets by execution stage to guarantee that Large Language Models cannot silently omit or mutate parameters before tool execution.
Silent input transformation bugs occur when an LLM drops required arguments, injects null values, or coerces types before calling an external tool. The bojieli/ai-agent-book repository demonstrates a robust pattern for tool parameter fidelity in its staged-system-prompt implementation, using explicit schema definitions and fail-fast validation to eliminate this class of errors.
Define Strict JSON Schemas for Every Tool
Tool parameter fidelity starts with an unambiguous contract. In chapter10/staged-system-prompt/tools.py, the repository defines a helper function _tool that constructs OpenAI-compatible function definitions with strict validation rules.
The helper forces developers to declare every argument in properties, mark truly required fields in required, and explicitly forbids extra keys via additionalProperties: False:
# chapter10/staged-system-prompt/tools.py
def _tool(name: str, description: str, properties: dict, required: list) -> dict:
return {
"type": "function",
"function": {
"name": name,
"description": description,
"parameters": {
"type": "object",
"properties": properties,
"required": required,
"additionalProperties": False, # Rejects undeclared keys
},
},
}
# Example: strict schema for file writing
WRITE_FILE = _tool(
name="write_file",
description="Write a text file to the workspace.",
properties={
"path": {"type": "string", "description": "Relative file path"},
"content": {"type": "string", "description": "File contents"},
},
required=["path", "content"],
)
Setting additionalProperties: False is critical for tool parameter fidelity because it prevents the LLM from injecting unexpected fields that could be misinterpreted by downstream logic.
Validate Arguments Before Tool Dispatch
Schema definitions alone do not prevent runtime errors. The repository implements a centralized _dispatch_tool method that validates every incoming tool call against its registered schema before executing the underlying function.
According to the source code, the validation logic performs two critical checks:
- Presence verification: Ensures every key in the schema's
requiredlist exists in the incomingargumentsdict and is notNone - Type verification: Confirms each argument matches its declared JSON Schema type
# Conceptual implementation as seen in the agent logic
def _dispatch_tool(self, tool_name: str, arguments: dict):
schema = self._tool_schemas[tool_name]["function"]["parameters"]
# Verify required fields are present and non-null
for key in schema["required"]:
if key not in arguments or arguments[key] is None:
raise ValueError(f"Missing required argument '{key}' for tool '{tool_name}'")
# Verify types match schema definition
for key, spec in schema["properties"].items():
if key in arguments:
expected_type = _type_from_json(spec["type"])
if not isinstance(arguments[key], expected_type):
raise TypeError(f"Argument '{key}' must be of type {spec['type']}")
# Only execute if validation passes
return getattr(self, f"_tool_impl_{tool_name}")(arguments)
This fail-fast approach ensures that any silent transformation—such as the LLM omitting the content field or passing null for path—surfaces immediately as a clear exception rather than causing obscure failures in the tool implementation.
Isolate Tools by Execution Stage
The repository enforces stage-specific tool sets via the STAGE_TOOLS mapping in tools.py. This dictionary maps each execution phase to a distinct subset of tools, ensuring that a tool from a later stage cannot be invoked prematurely with an incomplete argument set.
The test file test_stage_contracts_are_distinct_and_tool_gated.py verifies that stages never share the same tool name, guaranteeing schema isolation. This design eliminates cross-stage leakage bugs where an agent might call a tool early with arguments intended for a different context.
Fail Fast on Malformed or Null Input
To maintain tool parameter fidelity under edge cases, the repository includes dedicated regression tests that intentionally violate schemas:
test_null_tool_args.py: PassesNonefor required arguments and confirms the agent raisesValueErrortest_null_question.py: Verifies the agent refuses anullquestion before dispatchtest_malformed_tool_json.py: Feeds invalid JSON to the agent and verifies it returns a diagnostic error instead of parsing partial data
These tests serve as regression guards. Any code change that reintroduces silent argument dropping or coercion will cause immediate test failures, preventing the bug from reaching production.
Summary
- Define explicit schemas using
additionalProperties: Falseto prevent LLMs from injecting unexpected fields - Centralize validation in a
_dispatch_toolmethod that checks required fields and types before execution - Isolate tool sets by stage using
STAGE_TOOLSto prevent cross-stage invocation with incompatible schemas - Write negative tests that pass null or malformed arguments to ensure the agent fails fast rather than silently transforming inputs
Frequently Asked Questions
What is tool parameter fidelity in AI agents?
Tool parameter fidelity is the guarantee that every argument passed to an external tool exactly matches its declared schema without silent omission, type coercion, or null injection. It ensures that the LLM cannot "forget" required fields or mutate values before tool execution, preventing hard-to-debug runtime failures.
How does JSON Schema prevent silent input transformation?
By declaring properties, required fields, and additionalProperties: False in the JSON Schema, the agent creates a machine-readable contract that is enforced at runtime. The _dispatch_tool method validates incoming arguments against this schema, raising explicit errors for missing keys or type mismatches rather than allowing the tool to execute with corrupted inputs.
Why is stage isolation important for tool validation?
Stage isolation via STAGE_TOOLS prevents an agent from calling a tool intended for a later execution phase with arguments collected during an earlier phase. This eliminates cross-stage leakage where incomplete context could lead to partial argument sets, ensuring each tool is only available when its full schema can be satisfied.
What tests should I write to enforce tool parameter fidelity?
Write unit tests that intentionally violate your schemas: pass None for required arguments (as in test_null_tool_args.py), submit malformed JSON (as in test_malformed_tool_json.py), and attempt to invoke tools outside their designated stages. These negative tests act as regression guards against silent input transformation bugs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →