Normandy.Tools.Examples.EnhancedCalculator behaviour (normandy v0.6.2)

View Source

Schema-based calculator tool demonstrating the new SchemaBaseTool approach.

This is an enhanced version of the Calculator tool that uses Normandy schemas for input definition, providing automatic validation and better error messages.

Comparison with Original Calculator

Original Approach (manual schema definition):

  • Manually define struct fields
  • Manually write JSON schema in input_schema/1
  • No automatic validation
  • Duplication between struct and schema

Schema-Based Approach (this module):

  • Define schema once with tool_schema
  • Automatic JSON schema generation
  • Built-in validation with detailed errors
  • Type coercion and default values
  • Format validation support

Examples

# Create and validate
iex> {:ok, calc} = EnhancedCalculator.validate(%{operation: "add", a: 5, b: 3})
iex> EnhancedCalculator.execute(calc)
{:ok, 8}

# Validation catches errors
iex> EnhancedCalculator.validate(%{operation: "invalid", a: 5, b: 3})
{:error, [%{path: [:operation], constraint: :enum, ...}]}

# Automatic through BaseTool protocol
iex> tool = %EnhancedCalculator{operation: "multiply", a: 4, b: 7}
iex> Normandy.Tools.BaseTool.run(tool)
{:ok, 28}

Summary

Callbacks

Executes the tool with validated inputs.

Functions

Validates input parameters against the tool's schema.

Validates and raises on error.

Callbacks

execute(struct)

@callback execute(struct()) :: {:ok, term()} | {:error, String.t()}

Executes the tool with validated inputs.

This function must be implemented by the tool. It receives a validated struct with all fields populated according to the schema.

Returns {:ok, result} on success or {:error, reason} on failure.

Examples

@impl Normandy.Tools.SchemaBaseTool
def execute(%__MODULE__{operation: "add", a: a, b: b}) do
  {:ok, a + b}
end

def execute(%__MODULE__{operation: "divide", a: _a, b: 0}) do
  {:error, "Division by zero"}
end

Functions

execute(enhanced_calculator)

get_json_schema()

validate(params)

@spec validate(map()) :: {:ok, struct()} | {:error, list()}

Validates input parameters against the tool's schema.

Returns {:ok, struct} on success or {:error, errors} on validation failure.

Examples

iex> Elixir.Normandy.Tools.Examples.EnhancedCalculator.validate(%{operation: "add", a: 5, b: 3})
{:ok, %Elixir.Normandy.Tools.Examples.EnhancedCalculator{operation: "add", a: 5, b: 3}}

iex> Elixir.Normandy.Tools.Examples.EnhancedCalculator.validate(%{operation: "invalid"})
{:error, [%{path: [:a], message: "is required", constraint: :required}]}

validate!(params)

@spec validate!(map()) :: struct()

Validates and raises on error.

Returns the validated struct or raises Normandy.Schema.ValidationError.