Skip to main content
Version: 0.3.x (0.3.0)

Class ValueObjectAIExtensions

Namespace: AdCodicem.ValueObjects.AI
Assembly: AdCodicem.ValueObjects.AI.dll

Describes value objects in the schemas Microsoft.Extensions.AI publishes, and answers a model that sends one a value its rules refuse with the rule, not with an exception the model never sees.

public static class ValueObjectAIExtensions

Inheritance​

object ← ValueObjectAIExtensions

Inherited Members​

object.Equals(object?), object.Equals(object?, object?), object.GetHashCode(), object.GetType(), object.MemberwiseClone(), object.ReferenceEquals(object?, object?), object.ToString()

Remarks​

AIFunctionFactory describes a tool's parameters from their JsonTypeInfo, and a value object, serialized by a converter of its own, has none to read: each value-object parameter is published as true, the schema that accepts anything, and the model has to guess its length, pattern, bounds and allowed values. Binding still validates each argument, through the generated converter, but FunctionInvokingChatClient answers the exception it throws with "Error: Function failed.", which tells the model nothing it can correct. The two calls together close both gaps:

AIFunction placeOrder = AIFunctionFactory.Create(
tools.PlaceOrder,
new AIFunctionFactoryOptions { JsonSchemaCreateOptions = new AIJsonSchemaCreateOptions().WithValueObjects() })
.WithValueObjectValidation();

Where reflection-based serialization is disabled, as native AOT disables it, the factory's default options describe no value object at all, and refuse to: hand it SerializerOptions whose resolver is a source-generated context naming and the types of the parameters and of the result.

Methods​

WithValueObjectValidation(AIFunction)​

Wraps a function so that an argument a value object refuses is answered with its rule, not an exception.

public static AIFunction WithValueObjectValidation(this AIFunction function)

Parameters​

function AIFunction

The function, built from a method by .

Returns​

AIFunction

The wrapping function, or function itself when it wraps one already.

Remarks​

Before the function binds its arguments, each argument of a value-object parameter is read as the binding reads it, through the contract the function's serializer options hold for the parameter, which runs the value object's converter and its rules. The first refused, in the order of the parameters, is returned instead of calling the function, as a JSON object FunctionInvokingChatClient hands the model as it is:

{"error":"invalid_argument","argument":"quantity","code":"value_object.out_of_range","message":"The value is not a valid Quantity: The value must be less than or equal to 100."}

The message is the converter's, which names the value object and the rule, never the value sent; where the converter leaves it to System.Text.Json, for a number its underlying type cannot hold, or where a converter of the application's own refuses the value with an exception of its own, it is The value is not a valid Quantity., naming the value object alone. An argument the value object cannot read at all is value_object.not_parsable, unless a converter of the application's own carries a code; an absent one the parameter has no default for, and a null for a value object that cannot be null, which the binding would pass on as an uninitialized instance, are value_object.required. A collection, a dictionary or an object is read the same way, and answered for a value object it holds, under the parameter's name; any other error is left to the function, which throws it as it would without the wrapper.

An instance of the parameter's type is passed on as it is. Text or a number, which the binding converts through a JSON round trip of its own rather than refuses, is read as the binding converts it: text that may be JSON as JSON first, then the value written through the contract of its own type and read back; it is refused only when neither reading takes it.

The parameters are read from , once: a function no method backs, or whose parameters cannot hold a value object, is called as it is. A parameter a BindParameter callback binds, while the schema still lists it, is read as the serializer would read it.

Exceptions​

ArgumentNullException

function is null.

WithValueObjects(AIJsonSchemaCreateOptions?)​

Returns a copy of the options whose describes each value object with the rules declared on it, after any transform the options already carry.

public static AIJsonSchemaCreateOptions WithValueObjects(this AIJsonSchemaCreateOptions? options)

Parameters​

options AIJsonSchemaCreateOptions?

The options to copy, or null for .

Returns​

AIJsonSchemaCreateOptions

A copy of the options, every other setting kept; the options given are left as they are.

Remarks​

Each value object, alone, nullable, or held by a collection, a dictionary or an object, is described as its underlying value under : its JSON type alone, its lengths, pattern and numeric bounds, a closed set of known values as enum, a date bound as a sentence of the description, its description after the one a [Description] gives the parameter, and its example; a format JSON Schema does not define moves into the description. A transform the options already carry runs first, and this one completes what it wrote.

Under OpenAI's strict mode, Microsoft.Extensions.AI.OpenAI moves the lengths, the pattern, the bounds and the format into the description, and keeps type, enum and examples: the rules still reach the model.