Skip to main content
Version: v5.0

Custom tool

You can create your own tool on the platform and make API, RAG, and database calls from the tool.

Tool class object#

  {    "_name": "GetAssetsTool",    "_description": "The tool gets the asset based on the given criteria",    "_userType": "GetAssetsTool",                 "_namespaces": ["Namespace_EleSnXBw"],    "_toolClass": "GetAssetsTool"  }
PropertyTypeDescription
_nameStringThe tool name. The _name, _userType, and _toolClass properties should have the same value.
_descriptionStringEnter a description for the tool.
_userTypeStringThe _name, _userType, and _toolClass properties should have the same value.
_toolClassStringThe class name in your tool script used to extend the abstract class. The _name, _userType, and _toolClass properties should have the same value.

AbstractTool and Zod#

AbstractTool#

You can write custom tools by extending the AbstractTool class provided in the @dtplatform/agent-core platform library.

Zod#

Use Zod, a schema validation library for TypeScript, to define the schema for the arguments that the tool's call methods receive.

Permissions#

Only platform managers can upload script content to a custom tool. App developers must send script content to them for upload.

Language#

Only TypeScript or JavaScript​ scripts are accepted.

Creating a custom tool#

  1. Create the tool resource using IafAISvc.createTools:

    const tool = await IafAISvc.createTools([  {    "_name": "GetAssetsTool",    "_description": "The tool gets the asset based on the given criteria",    "_userType": "GetAssetsTool",                 "_namespaces": ["Namespace_EleSnXBw"],    "_toolClass": "GetAssetsTool"  }])
  2. Write the tool script content:

    i. Import AbstractTool, zod, and the platform APIs you require:

    import { AbstractTool } from '@dtplatform/agent-core';import { z } from 'zod';import * as PlatformAPI from '@dtplatform/platform-api';const { IafItemSvc } = PlatformAPI;

    ii. Define the schema for the Tool input parameters using zod:

    const toolSchema = z.object({  name: z.string().optional().nullable().describe('Filter by asset name. Supports regex'),  dtCategory: z.string().optional().nullable().describe('Filter by the dtCategory property. Supports regex'),  dtType: z.string().optional().nullable().describe('Filter by dtType property. Supports regex'),  _pageSize: z.string().optional().nullable().describe('Sets the number of results to return per Page in the response'),  _offset: z.string().optional().nullable().describe('Sets the number of results to skip in the Page response. For example, set to `10` to skip the first 10 results.')});

    iii. Create a your tool class that extends the AbstractTool class, then initialize the properties and schema:

    export default class GetAssetsTool extends AbstractTool {  name: string = 'GetAssetsTool';  description: string = 'Helps to retrieve Assets based on the provided criteria.';  requestContext: any = {};  schema: any = toolSchema;
      constructor(...args: any[]) {    super(...args);    const [{ requestContext }] = args;    this.requestContext = requestContext;  }  ...}

    iv. Create a _call method, which serves as a placeholder where you can place your API, RAG, or database calls. You can also add private class methods outside the _call method:

    ...  async _call(args: z.infer<typeof toolSchema>) {    let criteria: any = { '$or': [] };    let options: any = {};    let response: any = {};    if (args.name || args.dtCategory || args.dtType) {      if (args.name) {        criteria['$or'].push({          'Asset Name': {            '$regex': this.toRegexString(args.name),            '$options': 'i'          }        });      }      if (args.dtCategory) {        criteria['$or'].push({          'properties.dtCategory.val': {            '$regex': this.toRegexString(args.dtCategory),            '$options': 'i'          }        });      }      if (args.dtType) {        criteria['$or'].push({          'properties.dtType.val': {            '$regex': this.toRegexString(args.dtType),            '$options': 'i'          }        });      }      if (args._pageSize) {        options['_pageSize'] = parseInt(args._pageSize, 10);      }      if (args._offset) {        options['_offset'] = parseInt(args._offset, 10);      }      let colQuery = {        query: {          _userType: 'iaf_ext_asset_coll',          _itemClass: 'NamedUserCollection'        }      };      const colOptions = {        project: { _userType: 1, _itemClass: 1 },        sort: { _name: 1 },        page: { _offset: 0, _pageSize: 1 }      };      const colResponse = await IafItemSvc.getNamedUserItems(        colQuery,        this.requestContext,        colOptions      );      let assetCollection: any = null;      if (colResponse && Array.isArray(colResponse._list) && colResponse._list.length > 0) {        assetCollection = colResponse._list[0];        if (assetCollection && assetCollection._id) {          response = await IafItemSvc.getRelatedItems(            assetCollection._id,            {query: criteria},            this.requestContext,            options                      );        }      }    }    return response;  }
      //private class methods  toRegexString(str) {    const quoted = str.match(/^'(.*)'$/);    if (quoted) {      const escaped = quoted[1].replace(/[.*+?^${}()|[\]\\]/g, '\\$&');      return `.*(${escaped}).*`;    }    const terms = str      .split(/\s+/)      .map(term => term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));    return `.*(${terms.join('|')}).*`;  }
    
  3. The Platform Manager uploads the source code using IafAISvc.uploadToolSourceCode:

    //code as textawait IafAISvc.uploadToolSourceCode({  "_content": "Your script goes here"});//or fileawait IafAISvc.uploadToolSourceCode({  "_file": .ts file});