Skip to content

Creating Sorts

Sorts are the type system of the Reasoning Layer. They form a lattice with multiple inheritance, feature declarations, and inter-feature constraints. Every Psi-term (data instance) belongs to a sort.

Creating a single sort

Use client.sorts.createSort() to create a sort. The method accepts a CreateSortRequest and returns the created SortDto.

import { ReasoningLayerClient } from '@kortexya/reasoninglayer';
const client = new ReasoningLayerClient({
baseUrl: 'https://platform.ovh.reasoninglayer.ai',
tenantId: 'my-tenant-uuid',
auth: { mode: 'cookie' },
});
const person = await client.sorts.createSort({
name: 'person',
description: 'A human being',
});
console.log(person.id); // UUID assigned by the server
console.log(person.name); // "person"

Using the SortBuilder

The SortBuilder provides a fluent API for constructing complex sort definitions with features, parents, and constraints.

import { SortBuilder } from '@kortexya/reasoninglayer';
const request = SortBuilder.create('employee')
.parent(personSortId)
.feature({
name: 'salary',
required: true,
constraint: { type: 'IntegerRange', value: { min: 0, max: 10_000_000 } },
})
.feature({
name: 'department',
required: true,
expectedSort: 'department',
})
.feature({
name: 'email',
required: false,
constraint: { type: 'StringPattern', value: '^[^@]+@[^@]+$' },
})
.boundConstraint({
constraintType: 'upper',
target: 'endDate',
sourcePath: 'company.dissolutionDate',
})
.description('An employee at a company')
.build();
const employee = await client.sorts.createSort(request);

Deterministic UUIDs

You can assign a specific UUID to a sort, which is useful for homoiconic cross-references between sorts, rules, and facts.

const request = SortBuilder.create('sensor_reading')
.withId('550e8400-e29b-41d4-a716-446655440000')
.feature({ name: 'value', required: true })
.build();

Multiple inheritance

Sorts support multiple parents. Call .parent() multiple times or use .parents() with an array.

const request = SortBuilder.create('teaching_assistant')
.parent(studentSortId)
.parent(staffSortId)
.feature({ name: 'courses_assisting', required: true })
.build();
// Equivalent:
const request2 = SortBuilder.create('teaching_assistant')
.parents([studentSortId, staffSortId])
.feature({ name: 'courses_assisting', required: true })
.build();

Bulk creation with name-based parents

When defining an entire hierarchy at once, use bulkCreateSorts. Unlike createSort, parent references use sort names (not UUIDs), which are resolved server-side.

const result = await client.sorts.bulkCreateSorts({
sorts: [
{ name: 'animal', description: 'Base animal sort' },
{ name: 'mammal', parents: ['animal'] },
{ name: 'bird', parents: ['animal'] },
{ name: 'bat', parents: ['mammal'], description: 'A flying mammal' },
{
name: 'penguin',
parents: ['bird'],
features: [
{ name: 'colony_size', required: false },
],
},
],
});
console.log(result.createdCount); // 5
console.log(result.sortIds); // { animal: "uuid1", mammal: "uuid2", ... }
// Check for partial failures
if (result.errors && result.errors.length > 0) {
for (const err of result.errors) {
console.error(`Failed to create ${err.name}: ${err.error}`);
}
}

GLB and LUB computation

The Greatest Lower Bound (GLB) is the most specific common sort of two sorts. The Least Upper Bound (LUB) is the most general common supersort.

// Compute GLB
const glb = await client.sorts.computeGlb({
sort1Id: employeeSortId,
sort2Id: customerSortId,
});
if (glb.glb) {
console.log(`GLB sort: ${glb.glb}`);
} else {
console.log('No common lower bound exists');
}
// Compute LUB
const lub = await client.sorts.computeLub({
sort1Id: employeeSortId,
sort2Id: customerSortId,
});
if (lub.lub) {
console.log(`LUB sort: ${lub.lub}`);
}

Decoding a GLB as a type disjunction

When the GLB does not correspond to a single named sort, decodeGlb returns a human-readable disjunction.

const decoded = await client.sorts.decodeGlb({
sort1Id: sortA,
sort2Id: sortB,
});
console.log(decoded.formatted); // "int | real"
console.log(decoded.isBottom); // false
console.log(decoded.sortNames); // ["int", "real"]
console.log(decoded.sortIds); // ["uuid1", "uuid2"]

Convenience aliases

You can also use convenience aliases with simpler positional arguments:

const glb = await client.sorts.findCommonSubtype(employeeSortId, customerSortId);
const lub = await client.sorts.findCommonSupertype(employeeSortId, customerSortId);
const decoded = await client.sorts.explainCommonSubtype(sortA, sortB);

Sort comparison

Compare two sorts using one of six comparison operators.

// Check if employee is a subtype of person
const result = await client.sorts.compareSorts({
operator: 'isa_le',
sortA: 'employee',
sortB: 'person',
});
console.log(result.result); // true

Available operators:

OperatorMeaning
isa_leA is a subtype of or equal to B
isa_ltA is a strict subtype of B
isa_geA is a supertype of or equal to B
isa_gtA is a strict supertype of B
isa_eqA and B are the same sort
isa_cmpGeneral comparison (returns comparison result)

There is also a convenience method for subtype checking:

const isSub = await client.sorts.isSubtype(employeeSortId, personSortId);
console.log(isSub); // true

Sort similarity

Set and retrieve fuzzy similarity between two sorts. Similarity is a symmetric value from 0.0 to 1.0.

// Set similarity between two sorts
await client.sorts.setSortSimilarity({
sort1Id: catSortId,
sort2Id: dogSortId,
degree: 0.7,
});
// Retrieve similarity
const sim = await client.sorts.getSortSimilarity({
sort1Id: catSortId,
sort2Id: dogSortId,
});
console.log(sim.degree); // 0.7
// Direct children
const children = await client.sorts.getChildren(animalSortId);
// Direct parents
const parents = await client.sorts.getParents(mammalSortId);
// All ancestors (transitive)
const ancestors = await client.sorts.getAncestors(batSortId);
// All descendants (transitive)
const descendants = await client.sorts.getDescendants(animalSortId);
// Compatible sorts
const compatible = await client.sorts.getCompatible(mammalSortId);

Listing and deleting sorts

// List all sorts in the tenant
const allSorts = await client.sorts.listSorts();
// Delete a sort
await client.sorts.deleteSort(sortId);