How to Use Field Constraints (enum, ge, le, pattern, format) in Needle Tool Definitions
Needle converts Python Field metadata into JSON-Schema validation rules automatically when you use the @tool decorator, enabling strict validation of LLM arguments before your functions execute.
The Needle framework provides a lightweight system for defining agent tools using Python type hints. Located in needle/agent/tools.py, the Field class captures validation rules—such as numeric bounds, regex patterns, and enumerated values—and injects them into the JSON-Schema generated for Large Language Model (LLM) function calling.
Understanding the Field Class in needle/agent/tools.py
The Field class definition resides at lines 18‑33 of needle/agent/tools.py. It acts as a container for validation metadata that cannot be expressed by standard Python type annotations alone.
When you instantiate Field, you can provide constraints such as:
enum: A list of allowed valuesge/le: Greater-than-or-equal and less-than-or-equal numeric boundsgt/lt: Strictly greater-than and less-than boundspattern: Regular expression for string validationformat: Semantic format hints like"email"or"uri"min_items/max_items/unique_items: Constraints for list-type parameters
These attributes remain attached to the parameter definition until schema generation occurs.
How Needle Builds JSON-Schema from Field Constraints
When a function is decorated with @tool, Needle invokes build_schema(fn) (lines 11‑41) to construct the tool's JSON-Schema descriptor. The process extracts Field constraints and maps them to standard JSON-Schema keywords.
The Schema Generation Pipeline
For each annotated parameter, Needle executes three specific steps:
- Type Extraction: The
_json_typehelper (lines 57‑82) derives the base JSON type (e.g.,"string","number","array") from the Python annotation. - Field Extraction: If the annotation uses
Annotated[..., Field(...)], the_field_offunction (lines 85‑92) retrieves theFieldinstance. - Constraint Application: The
field.apply(schema)method (lines 36‑49) merges non-Noneconstraints into the schema object.
The apply Method Implementation
The apply method (lines 44‑47) iterates through the Field attributes and translates them into JSON-Schema equivalents:
# Simplified logic from needle/agent/tools.py
if field.enum is not None:
schema["enum"] = field.enum
if field.ge is not None:
schema["minimum"] = field.ge
if field.pattern is not None:
schema["pattern"] = field.pattern
# ... etc
This ensures that the LLM receives a schema with native validation keywords, causing invalid argument payloads to be rejected before your tool function ever runs.
Field Constraint Reference and Mapping
The following table illustrates how Field arguments map to JSON-Schema keywords according to the source implementation in needle/agent/tools.py:
| Field Argument | JSON-Schema Keyword | Validation Behavior |
|---|---|---|
enum=[...] |
"enum" |
Value must match one of the listed items |
ge=... |
"minimum" |
Numeric value must be ≥ specified bound |
le=... |
"maximum" |
Numeric value must be ≤ specified bound |
gt=... |
"exclusiveMinimum" |
Numeric value must be > specified bound |
lt=... |
"exclusiveMaximum" |
Numeric value must be < specified bound |
pattern="..." |
"pattern" |
String must match the regular expression |
format="..." |
"format" |
String must satisfy semantic format (e.g., email) |
min_items=... |
"minItems" |
Array must contain at least N elements |
max_items=... |
"maxItems" |
Array must contain at most N elements |
unique_items=True |
"uniqueItems" |
Array must contain unique items |
Practical Code Examples for Needle Field Constraints
To use these constraints in your own agent tools, wrap the parameter type with Field() inside an Annotated hint or use the direct shorthand syntax supported by Needle's decorator.
Enum Constraints
Restrict a parameter to specific allowed values:
from needle import tool, Field
@tool
def set_mode(mode: Field(enum=["fast", "slow"])) -> str:
"""Select the operating mode."""
return f"Mode set to {mode}"
This generates a schema containing "enum": ["fast", "slow"] for the mode property.
Numeric Bounds (ge, le, gt, lt)
Enforce valid ranges for integer or float parameters:
@tool
def resize_image(width: Field(ge=64, le=4096),
height: Field(gt=0, lt=5000)) -> str:
"""Resize an image to the given dimensions."""
return f"Resized to {width}×{height}"
The resulting schema includes "minimum": 64 and "maximum": 4096 for width, plus "exclusiveMinimum": 0 and "exclusiveMaximum": 5000 for height.
String Pattern and Format Validation
Validate email formats or enforce naming conventions:
@tool
def register_user(email: Field(format="email"),
username: Field(pattern="^[a-zA-Z][a-zA-Z0-9_]{2,15}$")) -> str:
"""Create a new user account."""
return f"User {username} registered with {email}"
The format="email" triggers JSON-Schema semantic validation, while pattern applies a custom regex constraint.
Collection Constraints
Control the size and uniqueness of list parameters:
@tool
def send_bulk_emails(recipients: Field(min_items=1,
max_items=100,
unique_items=True)):
"""Send one email to each unique recipient."""
return f"Sent to {len(recipients)} addresses"
This emits "minItems": 1, "maxItems": 100, and "uniqueItems": true in the generated schema.
Summary
- Import
Fieldfromneedle/agent/tools.py(exposed vianeedlepackage) to add validation metadata beyond basic types. build_schema()automatically extractsFieldinstances fromAnnotatedtype hints and converts them to JSON-Schema constraints.- Constraint mapping follows standard JSON-Schema:
gebecomes"minimum",patternbecomes"pattern",enumbecomes"enum", etc. field.apply(schema)(lines 36‑49) performs the actual dictionary update, ensuring only specified constraints appear in the final output.- Validation occurs pre-execution: The LLM receives the constraints, and Needle validates inputs before calling your function, preventing invalid data from reaching business logic.
Frequently Asked Questions
What happens if I provide a value outside the ge/le bounds?
Needle's tool executor validates arguments against the generated JSON-Schema before invoking your function. If the LLM attempts to provide a value outside the specified ge or le bounds (e.g., a number below the minimum), the validation fails and the tool call is rejected with a schema-validation error.
Can I combine multiple constraints on a single Field?
Yes. The Field class accepts multiple constraint arguments simultaneously. For example, Field(ge=0, le=100, enum=[10, 20, 50]) creates a schema that enforces both the numeric range and the specific enumerated values, requiring the input to satisfy both conditions.
Does the pattern constraint use Python regex syntax?
Yes. Needle passes the pattern string directly to the JSON-Schema "pattern" keyword, which uses JavaScript-compatible regular expressions. While Python and JavaScript regex are largely compatible, avoid Python-specific features like named groups or verbose mode flags to ensure the LLM's validation layer interprets the pattern correctly.
Where can I find the complete implementation of Field and build_schema?
The core implementation resides in needle/agent/tools.py at the repository root. Specifically:
- Lines 18‑33 define the
Fielddataclass and its attributes. - Lines 11‑41 implement
build_schema()and the constraint application logic. - Lines 85‑92 handle extraction of
Fieldinstances fromAnnotatedtypes.
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 →