Skip to main content
Version: v5.1

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 collectionslet 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    );