Skip to main content
Version: v5.2

Constructing a deep related item schema for rvt_element_props

A SchemaDefinition describes the properties of the project's collections and their related items in the Item Service. An agent with RelatedQueryTool uses this when constructing a query.

Related Items are described in the _itemTypes array and a schema is generated for each collection by analyzing its first related item. While in most cases this property description is sufficient, each Related Item in the rvt_element_props collection has varying and inconsistant properties: for the purposes of an Agent being able to query any property based on a user prompt, this requires a more in-depth schema which describes all possible properties.

  1. Find the element props related item schema in the _itemTypes array. By default its generated _typeName property is RevitElementProps.

    const elemPropsItemType = generatedSchemaDef._itemTypes.find(
    (it) => it._typeName === "RevitElementProps"
    );
  2. Nest the new property descriptions in <myItemType>._properties.properties._properties using a formatting function you create, such as formatElemPropsItemType in this case.

    const updatedElemsPropsItemType = {
    ...elemPropsItemType,
    _properties: {
    ...elemPropsItemType._properties,
    properties: {
    ...elemPropsItemType._properties.properties,
    _properties: {
    ...await formatElemPropsItemType(PlatformApi, ctx)
    }
    }
    }
    };
  3. Constructs a schema for each distinct property. formatElemPropsItemType takes all the distinct element properties, then constructs a schema for each one.

    First, it gets the rvt_element_props collection's related items using IafItemSvc.getRelatedItems:

    const formatElemPropsItemType = async (PlatformApi, ctx) => {
    const { IafItemSvc } = PlatformApi;
    const elemPropsCollection = await IafItemSvc.getNamedUserItems({
    query: { _userType: "rvt_element_props" }
    },
    ctx,
    undefined
    );
    const relatedItems = await IafItemSvc.getRelatedItems(
    elemPropsCollection._list[0]._userItemId,
    undefined,
    ctx,
    undefined
    );
    ...
    }

    It reduces the related items to an object with unique properties only:

    const uniqueProperties = {};
    if (relatedItems && Array.isArray(relatedItems._list)) {
    relatedItems._list.forEach(item => {
    if (item && item.properties && typeof item.properties === 'object') {
    Object.entries(item.properties).forEach(([propName, propValue]) => {
    if (!(propName in uniqueProperties)) {
    uniqueProperties[propName] = propValue;
    }
    });
    }
    });
    }
    console.log(`Found ${Object.keys(uniqueProperties).length} unique properties.`);

    It creates a schema definition for each property with the following structure:

    {
    "myProp": {
    "_type": "object",
    "_properties": {
    "<nestedPropName>": {
    "_type": "<type>"
    }
    }
    }
    }

    For more information, see the following schema for the Building Story property and its nested properties:

    "Building Story": {
    "_type": "object",
    "_properties": {
    "val": {
    "_type": "boolean"
    },
    "name": {
    "_type": "string"
    },
    "dName": {
    "_type": "string"
    },
    "id": {
    "_type": "number"
    }
    }
    },

    The following code constructs a this schema for each property in the uniqueProperties object:

    const schema = {};
    for (const [propName, propObj] of Object.entries(uniqueProperties)) {
    schema[propName] = {
    _type: "object",
    _properties: {}
    };
    for (const [key, val] of Object.entries(propObj)) {
    schema[propName]._properties[key] = {
    _type: inferPropType(val) //uses simple typeof logic
    };
    }
    }
    return schema;
  4. Update the schema definition using IafItemSvc.updateSchemaDefinitionsPartial:

    //Post the update to the Item Service
    const updatedSchemaDef = await IafItemSvc.updateSchemaDefinitionsPartial(
    {
    _itemTypes: [
    ...itemTypes.filter(it =>
    it._typeName !== updatedElemsPropsItemType._typeName
    ),
    updatedElemsPropsItemType
    ]
    },
    ctx,
    undefined
    );

Mapping collections to updated schema

Note: For a single model project, you can map the NamedUserCollections here once and for all; for multi-model support, this mapping occurs dynamically and must be done each time the current model changes. For more information, see [].

You must update each Named User Collection you want an LLM to query by adding the itemType name to the collection's _itemTypes array.

  1. Get the collections you want to update, which in this case are the "rvt_elements", "rvt_element_props", "rvt_type_elements" collections.

    // get all element collections
    let userColls = await IafItemSvc.getNamedUserItems({ query: {
    _userType: { $in: [
    "rvt_elements", "rvt_element_props", "rvt_type_elements"
    ]
    }}},
    ctx,
    undefined
    );
    userColls = userColls._list;

    const rvtElementsColl = userColls.find(
    col => col._userType === "rvt_elements"
    );
    const rvtElementPropsColl = userColls.find(
    col => col._userType === "rvt_element_props"
    );
    const rvtTypeElemsColl = userColls.find(
    col => col._userType === "rvt_type_elements"
    );

Update each collection with its relevant itemType name from the SchemaDefinition:

rvtElementsColl._itemTypes = ["RevitElement"];
rvtElementPropsColl._itemTypes = ["RevitElementProps"];
rvtTypeElemsColl._itemTypes = ["RevitTypeElement"];

const rvtElements = await IafItemSvc.updateNamedUserItem(
rvtElementsColl,
ctx,
undefined
);
const rvtElementProps = await IafItemSvc.updateNamedUserItem(
rvtElementPropsColl,
ctx,
undefined
);
const rvtTypeElems = await IafItemSvc.updateNamedUserItem(
rvtTypeElemsColl,
ctx,
undefined
);