How to Apply Field Constraints Using `needle.Field`: A Complete Guide with Code Examples

needle.Field is a lightweight helper class that injects JSON‑Schema validation constraints into function parameters decorated with @needle.tool, automatically enriching the generated tool schema.

When building AI tools with the Needle framework, you often need to specify validation rules—ranges, patterns, enums, descriptions—directly on function parameters. The needle.Field class provides a declarative way to do this without leaving your Python code.


What Is needle.Field?

needle.Field lives in [needle/agent/tools.py](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) and serves as a constraint container. When you use it as a parameter default in a @tool‑decorated function, Needle's schema generator detects it and merges its values into the final JSON‑Schema definition.

The class handles three core responsibilities according to the source code:

  • Storage: Captures constraint values (description, enum, minimum, maximum, pattern, etc.) in __init__.
  • Detection: Provides has_default() to determine if a parameter should be optional.
  • Merging: Offers apply(schema) to inject constraints into a schema dictionary.

How Field Constraints Work in Practice

Needle's tool generation pipeline follows this flow, as implemented in build_schema:

  1. Function signature inspection extracts parameter names and type hints.
  2. Each type hint is converted to a base JSON‑Schema type (_json_type).
  3. If a parameter default is a Field instance (detected via _field_of), field.apply(schema) is called.
  4. The apply method iterates over supported constraint keys and adds any non‑None values to the schema.

This design keeps your validation logic co‑located with your function definition rather than scattered in separate schema files.


Supported Field Constraints

Based on the Field.apply implementation in [needle/agent/tools.py](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py#L36-L49), you can specify:

Constraint JSON‑Schema Keyword Description
description description Human‑readable parameter explanation
enum enum List of allowed values (converted from iterable)
const const Single fixed value (when not _MISSING)
ge / le minimum / maximum Numeric inclusive bounds
gt / lt exclusiveMinimum / exclusiveMaximum Numeric exclusive bounds
pattern pattern Regular expression for string validation
default default Default value used when parameter is omitted

Code Example: Numeric Constraints with ge and le

Here's how to apply range validation to a numeric parameter:

from needle.agent.tools import Field, tool

@tool
def add(
    a: int,
    b: int = Field(
        default=0,
        description="Second addend",
        ge=0,      # minimum: 0

        le=100,    # maximum: 100

    ),
) -> int:
    """Returns the sum of two integers."""
    return a + b

The generated JSON‑Schema includes the constraints:

{
  "name": "add",
  "parameters": {
    "type": "object",
    "properties": {
      "a": { "type": "integer" },
      "b": {
        "type": "integer",
        "description": "Second addend",
        "minimum": 0,
        "maximum": 100,
        "default": 0
      }
    },
    "required": ["a"]
  }
}

Note that a appears in required because it has no Field default, while b is optional.


Code Example: String Constraints with enum and pattern

For enumerated string values, combine enum with pattern validation:

from needle.agent.tools import Field, tool

@tool
def set_mode(
    mode: str = Field(
        default="auto",
        enum=["auto", "manual", "off"],
        pattern="^(auto|manual|off)$",
        description="Operating mode of the device"
    )
) -> None:
    """Sets the device mode."""
    pass

Resulting schema output:

{
  "name": "set_mode",
  "parameters": {
    "type": "object",
    "properties": {
      "mode": {
        "type": "string",
        "description": "Operating mode of the device",
        "enum": ["auto", "manual", "off"],
        "pattern": "^(auto|manual|off)$",
        "default": "auto"
      }
    },
    "required": []
  }
}

The enum constraint is automatically converted to a list, and pattern provides regex‑based validation for additional safety.


Integration with typing.Annotated

Needle also supports attaching Field constraints via typing.Annotated, allowing you to preserve non‑Field default values. The build_schema function checks for Field instances through _field_of, which handles both default‑value and Annotated attachment.

from typing import Annotated
from needle.agent.tools import Field, tool

@tool
def configure(
    timeout: Annotated[int, Field(ge=1, le=300, description="Timeout in seconds")] = 30
) -> None:
    """Configure connection settings."""
    pass

This pattern separates the runtime default (30) from the schema constraints (Field).


Key Source Files and Methods

Component Location Purpose
Field class needle/agent/tools.py#L18 Constraint storage and apply logic
Field.__init__ needle/agent/tools.py#L18-L22 Parameter initialization
Field.apply needle/agent/tools.py#L36-L49 Schema enrichment implementation
build_schema needle/agent/tools.py#L11-L43 Core schema generation function
tool decorator needle/agent/tools.py#L64-L67 Attaches schema via _needle_tool

Summary

  • needle.Field provides declarative JSON‑Schema constraints directly in Python function signatures.
  • Constraints are merged during build_schema via the Field.apply method, supporting description, enum, minimum, maximum, pattern, and more.
  • Parameters with Field defaults become optional; those without remain required.
  • Both default‑value and Annotated attachment patterns are supported for flexibility.

Frequently Asked Questions

How does Needle detect which parameters are required?

Required parameters are determined by Field.has_default(). If a parameter's default is a Field instance with an explicit default value (or any default at all), the parameter is considered optional and excluded from the required array in the JSON‑Schema. Parameters without any default value are marked required.

Can I use needle.Field without a default value?

Yes, through typing.Annotated. This lets you attach constraints while keeping a separate runtime default, or even requiring the parameter. The build_schema function in [needle/agent/tools.py](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) extracts Field instances from Annotated metadata via the _field_of helper.

What happens if I specify both ge and gt on the same field?

Both translate to JSON‑Schema keywords (minimum for ge, exclusiveMinimum for gt). The source code's apply method simply adds whichever values are non‑None, so specifying both creates a schema with both constraints. Ensure your values are logically consistent—JSON‑Schema validators will enforce both rules.

Is pattern validated at runtime or only in the schema?

The pattern constraint is emitted into the JSON‑Schema only. Needle does not perform runtime validation of parameter values against the pattern; the receiving system (typically an LLM or downstream API) is responsible for enforcing regex constraints based on the schema.

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 →