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 values
  • ge / le: Greater-than-or-equal and less-than-or-equal numeric bounds
  • gt / lt: Strictly greater-than and less-than bounds
  • pattern: Regular expression for string validation
  • format: 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:

  1. Type Extraction: The _json_type helper (lines 57‑82) derives the base JSON type (e.g., "string", "number", "array") from the Python annotation.
  2. Field Extraction: If the annotation uses Annotated[..., Field(...)], the _field_of function (lines 85‑92) retrieves the Field instance.
  3. Constraint Application: The field.apply(schema) method (lines 36‑49) merges non-None constraints 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 Field from needle/agent/tools.py (exposed via needle package) to add validation metadata beyond basic types.
  • build_schema() automatically extracts Field instances from Annotated type hints and converts them to JSON-Schema constraints.
  • Constraint mapping follows standard JSON-Schema: ge becomes "minimum", pattern becomes "pattern", enum becomes "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 Field dataclass and its attributes.
  • Lines 11‑41 implement build_schema() and the constraint application logic.
  • Lines 85‑92 handle extraction of Field instances from Annotated types.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →