import { z } from 'zod' import { DynamicStructuredTool } from '../OpenAPIToolkit/core' import { secureFetch } from '../../../src/httpSecurity' export const desc = `Use this when you need to execute a DELETE request to remove data from a website.` export interface Headers { [key: string]: string } export interface RequestParameters { headers?: Headers url?: string name?: string queryParamsSchema?: string description?: string maxOutputLength?: number } // Base schema for DELETE request const createRequestsDeleteSchema = (queryParamsSchema?: string) => { // If queryParamsSchema is provided, parse it and add dynamic query params if (queryParamsSchema) { try { const parsedSchema = JSON.parse(queryParamsSchema) const queryParamsObject: Record = {} Object.entries(parsedSchema).forEach(([key, config]: [string, any]) => { let zodType: z.ZodTypeAny = z.string() // Handle different types if (config.type === 'number') { zodType = z.string().transform((val) => Number(val)) } else if (config.type === 'boolean') { zodType = z.string().transform((val) => val === 'true') } // Add description if (config.description) { zodType = zodType.describe(config.description) } // Make optional if not required if (!config.required) { zodType = zodType.optional() } queryParamsObject[key] = zodType }) if (Object.keys(queryParamsObject).length > 0) { return z.object({ queryParams: z.object(queryParamsObject).optional().describe('Query parameters for the request') }) } } catch (error) { console.warn('Failed to parse queryParamsSchema:', error) } } // Fallback to generic query params return z.object({ queryParams: z.record(z.string()).optional().describe('Optional query parameters to include in the request') }) } export class RequestsDeleteTool extends DynamicStructuredTool { url = '' maxOutputLength = Infinity headers = {} queryParamsSchema?: string constructor(args?: RequestParameters) { const schema = createRequestsDeleteSchema(args?.queryParamsSchema) const toolInput = { name: args?.name || 'requests_delete', description: args?.description || desc, schema: schema, baseUrl: '', method: 'DELETE', headers: args?.headers || {} } super(toolInput) this.url = args?.url ?? this.url this.headers = args?.headers ?? this.headers this.maxOutputLength = args?.maxOutputLength ?? this.maxOutputLength this.queryParamsSchema = args?.queryParamsSchema } /** @ignore */ async _call(arg: any): Promise { const params = { ...arg } const inputUrl = this.url if (!inputUrl) { throw new Error('URL is required for DELETE request') } const requestHeaders = { ...(params.headers || {}), ...this.headers } // Process URL and query parameters based on schema let finalUrl = inputUrl const queryParams: Record = {} if (this.queryParamsSchema && params.queryParams && Object.keys(params.queryParams).length > 0) { try { const parsedSchema = JSON.parse(this.queryParamsSchema) const pathParams: Array<{ key: string; value: string }> = [] Object.entries(params.queryParams).forEach(([key, value]) => { const paramConfig = parsedSchema[key] if (paramConfig && value !== undefined && value !== null) { if (paramConfig.in === 'path') { // Check if URL contains path parameter placeholder const pathPattern = new RegExp(`:${key}\\b`, 'g') if (finalUrl.includes(`:${key}`)) { // Replace path parameters in URL (e.g., /:id -> /123) finalUrl = finalUrl.replace(pathPattern, encodeURIComponent(String(value))) } else { // Collect path parameters to append to URL pathParams.push({ key, value: String(value) }) } } else if (paramConfig.in === 'query') { // Add to query parameters queryParams[key] = String(value) } } }) // Append path parameters to URL if any exist if (pathParams.length > 0) { let urlPath = finalUrl // Remove trailing slash if present if (urlPath.endsWith('/')) { urlPath = urlPath.slice(0, -1) } // Append each path parameter pathParams.forEach(({ value }) => { urlPath += `/${encodeURIComponent(value)}` }) finalUrl = urlPath } // Add query parameters to URL if any exist if (Object.keys(queryParams).length > 0) { const url = new URL(finalUrl) Object.entries(queryParams).forEach(([key, value]) => { url.searchParams.append(key, value) }) finalUrl = url.toString() } } catch (error) { console.warn('Failed to process queryParamsSchema:', error) } } else if (params.queryParams && Object.keys(params.queryParams).length > 0) { // Fallback: treat all parameters as query parameters if no schema is defined const url = new URL(finalUrl) Object.entries(params.queryParams).forEach(([key, value]) => { url.searchParams.append(key, String(value)) }) finalUrl = url.toString() } try { const res = await secureFetch(finalUrl, { method: 'DELETE', headers: requestHeaders }) if (!res.ok) { throw new Error(`HTTP Error ${res.status}: ${res.statusText}`) } const text = await res.text() return text.slice(0, this.maxOutputLength) } catch (error) { throw new Error(`Failed to make DELETE request: ${error instanceof Error ? error.message : 'Unknown error'}`) } } }