import { createLogger } from '@sim/logger' import type { ServiceNowReadParams, ServiceNowReadResponse } from '@/tools/servicenow/types' import { createBasicAuthHeader } from '@/tools/servicenow/utils' import type { ToolConfig } from '@/tools/types' const logger = createLogger('ServiceNowReadRecordTool') export const readRecordTool: ToolConfig = { id: 'servicenow_read_record', name: 'Read ServiceNow Records', description: 'Read records from a ServiceNow table', version: '1.0.0', params: { instanceUrl: { type: 'string', required: true, visibility: 'user-only', description: 'ServiceNow instance URL (e.g., https://instance.service-now.com)', }, username: { type: 'string', required: true, visibility: 'user-only', description: 'ServiceNow username', }, password: { type: 'string', required: true, visibility: 'user-only', description: 'ServiceNow password', }, tableName: { type: 'string', required: true, visibility: 'user-or-llm', description: 'Table name (e.g., incident, task, sys_user, change_request)', }, sysId: { type: 'string', required: false, visibility: 'user-or-llm', description: 'Specific record sys_id (e.g., 6816f79cc0a8016401c5a33be04be441)', }, number: { type: 'string', required: false, visibility: 'user-or-llm', description: 'Record number (e.g., INC0010001)', }, query: { type: 'string', required: false, visibility: 'user-or-llm', description: 'Encoded query string (e.g., "active=true^priority=1")', }, limit: { type: 'number', required: false, visibility: 'user-or-llm', description: 'Maximum number of records to return (e.g., 10, 50, 100)', }, offset: { type: 'number', required: false, visibility: 'user-or-llm', description: 'Number of records to skip for pagination (e.g., 0, 10, 20)', }, fields: { type: 'string', required: false, visibility: 'user-or-llm', description: 'Comma-separated list of fields to return (e.g., sys_id,number,short_description,state)', }, displayValue: { type: 'string', required: false, visibility: 'user-or-llm', description: 'Return display values for reference fields: "true" (display only), "false" (sys_id only), or "all" (both)', }, }, request: { url: (params) => { const baseUrl = params.instanceUrl.trim().replace(/\/$/, '') if (!baseUrl) { throw new Error('ServiceNow instance URL is required') } let url = `${baseUrl}/api/now/table/${params.tableName.trim()}` const queryParams = new URLSearchParams() if (params.sysId) { url = `${url}/${params.sysId.trim()}` } else if (params.number) { const numberQuery = `number=${params.number}` const existingQuery = params.query queryParams.append( 'sysparm_query', existingQuery ? `${existingQuery}^${numberQuery}` : numberQuery ) } else if (params.query) { queryParams.append('sysparm_query', params.query) } if (params.limit) { queryParams.append('sysparm_limit', params.limit.toString()) } if (params.offset !== undefined && params.offset !== null) { queryParams.append('sysparm_offset', params.offset.toString()) } if (params.fields) { queryParams.append('sysparm_fields', params.fields) } if (params.displayValue) { queryParams.append('sysparm_display_value', params.displayValue) } const queryString = queryParams.toString() return queryString ? `${url}?${queryString}` : url }, method: 'GET', headers: (params) => { if (!params.username || !params.password) { throw new Error('ServiceNow username and password are required') } return { Authorization: createBasicAuthHeader(params.username, params.password), Accept: 'application/json', } }, }, transformResponse: async (response: Response) => { try { const data = await response.json() if (!response.ok) { const error = data.error || data throw new Error(typeof error === 'string' ? error : error.message || JSON.stringify(error)) } const records = Array.isArray(data.result) ? data.result : [data.result] return { success: true, output: { records, metadata: { recordCount: records.length, }, }, } } catch (error) { logger.error('ServiceNow read record - Error processing response:', { error }) throw error } }, outputs: { records: { type: 'array', description: 'Array of ServiceNow records', }, metadata: { type: 'json', description: 'Operation metadata', }, }, }