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" }| Property | Type | Description |
|---|---|---|
_name | String | The tool name. The _name, _userType, and _toolClass properties should have the same value. |
_description | String | Enter a description for the tool. |
_userType | String | The _name, _userType, and _toolClass properties should have the same value. |
_toolClass | String | The 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#
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" }])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
_callmethod, which serves as a placeholder where you can place your API, RAG, or database calls. You can also add private class methods outside the_callmethod:... 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('|')}).*`; }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});