Overview
Implement typed predictors that provide type-safe field handling with automatic validation and parsing, similar to Pydantic in Python.
Description
Typed predictors ensure type safety at module boundaries by automatically validating and coercing inputs/outputs according to specified types. This reduces runtime errors and improves developer experience with better IDE support.
Key Features to Implement
- Type definitions for signature fields
- Automatic validation on input/output
- Type coercion with clear rules
- Custom type validators
- IDE-friendly type annotations
- Integration with existing Field system
Implementation Requirements
1. Type System Enhancement
module Desiru
module Types
class TypedField < Field
attr_reader :type_class, :validator
def initialize(name:, type:, description: nil, optional: false, validator: nil)
super(name: name, type: type, description: description, optional: optional)
@type_class = resolve_type_class(type)
@validator = validator
end
def validate_and_coerce(value)
# Skip nil for optional fields
return nil if value.nil? && optional
# Type coercion
coerced = coerce_value(value)
# Type validation
unless valid_type?(coerced)
raise ValidationError, "Expected #{type}, got #{coerced.class}"
end
# Custom validation
if @validator && \!@validator.call(coerced)
raise ValidationError, "Custom validation failed for #{name}"
end
coerced
end
private
def coerce_value(value)
case @type
when :integer
Integer(value) rescue raise ValidationError, "Cannot convert to integer"
when :float
Float(value) rescue raise ValidationError, "Cannot convert to float"
when :boolean
to_boolean(value)
when :array
Array(value)
when :hash
value.to_h rescue raise ValidationError, "Cannot convert to hash"
else
value
end
end
end
end
end
2. Typed Predictor Module
module Desiru
class TypedPredictor < Module
def initialize(signature:, **options)
super
setup_typed_fields
end
def forward(**inputs)
# Validate and coerce inputs
validated_inputs = validate_inputs(inputs)
# Execute prediction
result = super(**validated_inputs)
# Validate and coerce outputs
validate_outputs(result)
end
private
def setup_typed_fields
@typed_input_fields = {}
@typed_output_fields = {}
@signature.input_fields.each do |name, field|
@typed_input_fields[name] = Types::TypedField.new(
name: name,
type: field.type,
description: field.description,
optional: field.optional
)
end
@signature.output_fields.each do |name, field|
@typed_output_fields[name] = Types::TypedField.new(
name: name,
type: field.type,
description: field.description,
optional: field.optional
)
end
end
def validate_inputs(inputs)
validated = {}
@typed_input_fields.each do |name, field|
value = inputs[name] || inputs[name.to_s]
validated[name] = field.validate_and_coerce(value)
end
validated
end
end
end
3. Advanced Type Definitions
# Support for complex types
module Desiru::Types
# Enum type
class Enum < TypedField
def initialize(name:, values:, **options)
super(name: name, type: :enum, **options)
@allowed_values = values
end
def validate_and_coerce(value)
unless @allowed_values.include?(value)
raise ValidationError, "Value must be one of: #{@allowed_values.join(', ')}"
end
value
end
end
# Structured type
class Structured < TypedField
def initialize(name:, schema:, **options)
super(name: name, type: :structured, **options)
@schema = schema
end
def validate_and_coerce(value)
validate_against_schema(value, @schema)
end
end
# List with element type
class TypedList < TypedField
def initialize(name:, element_type:, **options)
super(name: name, type: :array, **options)
@element_type = element_type
end
def validate_and_coerce(value)
array = super(value)
array.map { |elem|
@element_type.validate_and_coerce(elem)
}
end
end
end
4. DSL for Typed Signatures
class TypedSignature < Signature
def self.define(&block)
builder = SignatureBuilder.new
builder.instance_eval(&block)
builder.build
end
class SignatureBuilder
def initialize
@input_fields = {}
@output_fields = {}
end
# DSL methods
def input(name, type, **options)
@input_fields[name] = create_typed_field(name, type, **options)
end
def output(name, type, **options)
@output_fields[name] = create_typed_field(name, type, **options)
end
def enum(name, values:, **options)
Types::Enum.new(name: name, values: values, **options)
end
def list_of(type)
Types::TypedList.new(element_type: type)
end
end
end
Example Usage
# Define typed signature
signature = Desiru::TypedSignature.define do
input :age, :integer, validator: ->(v) { v >= 0 && v <= 150 }
input :name, :string, description: "Person's full name"
input :interests, list_of(:string), optional: true
output :category, enum(values: ["child", "teen", "adult", "senior"])
output :summary, :string
end
# Create typed predictor
predictor = Desiru::TypedPredictor.new(
signature: signature,
model: "gpt-4"
)
# Type-safe usage
result = predictor.forward(
age: "25", # Automatically converted to integer
name: "Alice Smith"
)
# Result has validated category and summary
# This would raise ValidationError
result = predictor.forward(
age: "invalid", # Cannot convert to integer
name: "Bob"
)
Integration with IDE
# Generate RBS type signatures
class TypedPredictor
def generate_rbs
<<~RBS
class #{self.class.name}
def forward: (#{format_input_types}) -> { #{format_output_types} }
end
RBS
end
end
Testing Requirements
- Unit tests for each type coercion
- Validation error cases
- Complex type scenarios
- Performance impact measurement
- IDE integration tests
Priority
High - Significantly improves reliability and developer experience
Overview
Implement typed predictors that provide type-safe field handling with automatic validation and parsing, similar to Pydantic in Python.
Description
Typed predictors ensure type safety at module boundaries by automatically validating and coercing inputs/outputs according to specified types. This reduces runtime errors and improves developer experience with better IDE support.
Key Features to Implement
Implementation Requirements
1. Type System Enhancement
2. Typed Predictor Module
3. Advanced Type Definitions
4. DSL for Typed Signatures
Example Usage
Integration with IDE
Testing Requirements
Priority
High - Significantly improves reliability and developer experience