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.
Find the element props related item schema in the
_itemTypesarray. By default its generated_typeNameproperty isRevitElementProps.const elemPropsItemType = generatedSchemaDef._itemTypes.find( (it) => it._typeName === "RevitElementProps" );Nest the new property descriptions in
<myItemType>._properties.properties._propertiesusing a formatting function you create, such asformatElemPropsItemTypein this case.const updatedElemsPropsItemType = { ...elemPropsItemType, _properties: { ...elemPropsItemType._properties, properties: { ...elemPropsItemType._properties.properties, _properties: { ...await formatElemPropsItemType(PlatformApi, ctx) } } } };Constructs a schema for each distinct property.
formatElemPropsItemTypetakes all the distinct element properties, then constructs a schema for each one.First, it gets the
rvt_element_propscollection's related items usingIafItemSvc.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
uniquePropertiesobject: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;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.
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 );