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:
- Function signature inspection extracts parameter names and type hints.
- Each type hint is converted to a base JSON‑Schema type (
_json_type). - If a parameter default is a
Fieldinstance (detected via_field_of),field.apply(schema)is called. - The
applymethod iterates over supported constraint keys and adds any non‑Nonevalues 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.Fieldprovides declarative JSON‑Schema constraints directly in Python function signatures.- Constraints are merged during
build_schemavia theField.applymethod, supportingdescription,enum,minimum,maximum,pattern, and more. - Parameters with
Fielddefaults become optional; those without remain required. - Both default‑value and
Annotatedattachment 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →