Skip to content
Cascading Labs QScrape VoidCrawl Yosoi

Custom Types

When built-in types don’t cover your domain, register a custom type. Once registered, it works exactly like a built-in: the AI sees it in the manifest, and the coercion runs automatically during extraction.

Register a Coercion

One function, zero boilerplate. The decorator registers the coerce logic and replaces the name with a Field factory.

import re
from typing import Any
import yosoi as ys
@ys.register_coercion('phone', description='A phone number', country_code='+1')
def PhoneNumber(v: object, config: dict[str, Any], source_url: str | None = None) -> str:
"""Strip formatting and prepend a country code."""
raw = str(v).strip()
digits = re.sub(r'\D', '', raw)
if not digits:
raise ValueError(f'No digits found in phone value: {v!r}')
cc = config.get('country_code', '+1')
cc_digits = re.sub(r'\D', '', cc)
if digits.startswith(cc_digits):
return f'+{digits}'
return f'{cc}{digits}'

Decorator kwargs become the factory’s parameter schema:

# Default country code
us_phone: str = PhoneNumber()
# Override per field
uk_phone: str = PhoneNumber(country_code='+44')

Using Custom Types in a Contract

Registered coercions compose naturally with built-ins:

import yosoi as ys
class ContactPage(ys.Contract):
name: str = ys.Title()
us_phone: str = PhoneNumber()
uk_phone: str = PhoneNumber(country_code='+44')
website: str = ys.Url()

Custom types appear in Contract.generate_manifest(), so the AI knows about them during selector discovery.

FAQs

Which pattern should I use?

Use @register_coercion. It is the supported custom-type path.

Can custom types be used with list[T]?

Yes. Custom coercions run element-by-element on list fields, the same as built-in types.

How do I debug a coercion failure?

Raise a ValueError with a descriptive message inside your coerce function. Pydantic will surface it as a ValidationError with field context. Run with --debug to inspect the raw extracted values before coercion.

References

Pydantic. Pydantic Services Inc. Data validation library for Python. https://docs.pydantic.dev/