Working with Terms
Terms are the data instances of the Reasoning Layer. Each term belongs to a sort (type) and carries named features with typed values. Terms use the tagged ValueDto serialization format.
Creating a term
Section titled “Creating a term”Use plain JavaScript values for feature values. The SDK handles serialization to the tagged wire format automatically.
import { ReasoningLayerClient } from '@kortexya/reasoninglayer';
const client = new ReasoningLayerClient({ baseUrl: 'https://platform.ovh.reasoninglayer.ai', tenantId: 'my-tenant-uuid', auth: { mode: 'cookie' },});
const response = await client.terms.createTerm({ sortId: personSortId, ownerId: 'user-uuid', features: { name: 'Alice', age: 30, height: 1.72, active: true, },});Understanding TermResponse
Section titled “Understanding TermResponse”Term CRUD endpoints return TermResponse, not raw TermDto. The response includes validation state from the sort’s type witnesses.
const response = await client.terms.createTerm({ sortId: sortId, ownerId: 'user-uuid', features: { name: 'Bob' },});
// The term dataconst term = response.term;console.log(term.id); // UUIDconsole.log(term.sortId); // sort UUIDconsole.log(term.features); // { name: { type: "String", value: "Bob" } }
// Validation stateconsole.log(response.state); // "complete" | "residuated" | "no_witnesses"
if (response.state === 'residuated') { // Some witnesses could not be fully evaluated yet for (const rw of response.residualWitnesses ?? []) { console.log(`Witness ${rw.witnessId} waiting on: ${rw.trigger}`); }}
if (response.state === 'complete') { // All witnesses satisfied for (const wp of response.witnessProofs ?? []) { console.log(`Witness ${wp.witnessId} proved with certainty ${wp.certainty}`); }}The three states:
| State | Meaning |
|---|---|
complete |
All type witnesses are satisfied |
residuated |
Some witnesses are suspended (missing information) |
no_witnesses |
The sort has no witness requirements |
Value builders
Section titled “Value builders”For primitive types, use plain JavaScript values directly: strings, numbers, booleans, null (for uninstantiated), and arrays. The Value namespace is only needed for special types that cannot be expressed as plain JS values.
import { Value, FuzzyShape } from '@kortexya/reasoninglayer';
// References to other termsValue.reference(termId); // {"type": "Reference", "value": "uuid"}
// Fuzzy valuesValue.fuzzyScalar(0.5, 0.8);Value.fuzzyNumber(FuzzyShape.triangular(20, 22, 24));
// Set values (Smyth powerdomain)Value.set( ['definite-member-uuid'], // lower bound ['definite-uuid', 'possible-uuid'], // upper bound 'sort-constraint-id', // optional sort constraint);For primitive types (strings, numbers, booleans, null, arrays), pass plain JavaScript values directly – no builder needed. The Value namespace is only required for reference, fuzzyScalar, fuzzyNumber, and set, which have no plain JS equivalent.
Updating a term
Section titled “Updating a term”updateTerm applies a partial update. Only the features you provide are changed; omitted features remain unchanged.
const updated = await client.terms.updateTerm(termId, { features: { age: 31, email: 'alice@example.com', },});
console.log(updated.term.features);// age is now 31, email is added, name is unchangedGetting and deleting terms
Section titled “Getting and deleting terms”// Get a term by IDconst response = await client.terms.getTerm(termId);const term = response.term;
// Check if a term existsconst exists = await client.terms.termExists(termId);
// Delete a termawait client.terms.deleteTerm(termId);Listing and clearing terms
Section titled “Listing and clearing terms”// List all terms for the tenantconst allTerms = await client.terms.listTerms();
// Clear all termsawait client.terms.clearTerms();Bulk creation
Section titled “Bulk creation”Create many terms at once with bulkCreateTerms.
const result = await client.terms.bulkCreateTerms({ terms: [ { sortId: personSortId, ownerId: 'user-uuid', features: { name: 'Alice', age: 30, }, }, { sortId: personSortId, ownerId: 'user-uuid', features: { name: 'Bob', age: 25, }, }, { sortId: personSortId, ownerId: 'user-uuid', features: { name: 'Charlie', age: 40, }, }, ],});
console.log(result.termIds); // ["uuid1", "uuid2", "uuid3"]console.log(result.processingTimeMs); // 12Working with references
Section titled “Working with references”Terms can reference other terms using Value.reference().
// Create a departmentconst dept = await client.terms.createTerm({ sortId: departmentSortId, ownerId: 'user-uuid', features: { name: 'Engineering', },});
// Create an employee referencing the departmentconst emp = await client.terms.createTerm({ sortId: employeeSortId, ownerId: 'user-uuid', features: { name: 'Alice', department: Value.reference(dept.term.id), },});When a sort declares a feature’s range as an entity sort (department: department), that feature takes a reference. The engine refuses a scalar literal there with a 422, on every term write door (createTerm, updateTerm, bulkCreateTerms, OSFQL writes, actions.applyAction and inference.addFact):
Feature 'department' holds a string literal, which is incompatible with the declared range 'department' — write a reference to a 'department' termDo not send the id as a string (department: dept.term.id). Send Value.reference(dept.term.id). A range at or below real_type admits an integer literal.
Designating an existing term in OSFQL
Section titled “Designating an existing term in OSFQL”In an OSFQL write, a nested <sort>(__osf_term_id: "<id>") designates the existing term with that id. The engine stores a reference to it and mints nothing:
await client.osfql.execute( `INSERT employee(name: "Alice", department: department(__osf_term_id: "${dept.term.id}"));`,);The engine refuses the write, before it mints anything, when the id is not a UUID, names no term, names a term the caller cannot see, or names a term outside the nested pattern (here, a term that is not a department). In a MATCH, the same nested pattern filters on that identity.
Uninstantiated features
Section titled “Uninstantiated features”Use null for features whose value is not yet known. The system supports residuation – suspending computation until the value becomes available.
const partialTerm = await client.terms.createTerm({ sortId: personSortId, ownerId: 'user-uuid', features: { name: 'Alice', age: null, // unknown for now },});
// Later, fill in the missing valueawait client.terms.updateTerm(partialTerm.term.id, { features: { age: 30, },});