import { TableRow } from './types' import { ToolConfig, ToolResponse } from './types' /** * Transforms a table from the store format to a key-value object * @param table Array of table rows from the store * @returns Record of key-value pairs */ export const transformTable = (table: TableRow[] | null): Record => { if (!table) return {} return table.reduce( (acc, row) => { if (row.cells?.Key && row.cells?.Value !== undefined) { acc[row.cells.Key] = row.cells.Value } return acc }, {} as Record ) } interface RequestParams { url: string method: string headers: Record body?: string } /** * Format request parameters based on tool configuration and provided params */ export function formatRequestParams(tool: ToolConfig, params: Record): RequestParams { // Process URL const url = typeof tool.request.url === 'function' ? tool.request.url(params) : tool.request.url // Process method const method = params.method || tool.request.method || 'GET' // Process headers const headers = tool.request.headers ? tool.request.headers(params) : {} // Process body const hasBody = method !== 'GET' && method !== 'HEAD' && !!tool.request.body const bodyResult = tool.request.body ? tool.request.body(params) : undefined // Special handling for NDJSON content type const isNDJSON = headers['Content-Type'] === 'application/x-ndjson' const body = hasBody ? isNDJSON && bodyResult ? bodyResult.body : JSON.stringify(bodyResult) : undefined return { url, method, headers, body } } /** * Execute the actual request and transform the response */ export async function executeRequest( toolId: string, tool: ToolConfig, requestParams: RequestParams ): Promise { try { const { url, method, headers, body } = requestParams const externalResponse = await fetch(url, { method, headers, body }) if (!externalResponse.ok) { let errorContent try { errorContent = await externalResponse.json() } catch (e) { errorContent = { message: externalResponse.statusText } } // Use the tool's error transformer or a default message const error = tool.transformError ? tool.transformError(errorContent) : errorContent.message || `${toolId} API error: ${externalResponse.statusText}` console.error(`${toolId} error:`, error) throw new Error(error) } const transformResponse = tool.transformResponse || (async (resp: Response) => ({ success: true, output: await resp.json(), })) return await transformResponse(externalResponse) } catch (error: any) { return { success: false, output: {}, error: error.message || 'Unknown error', } } } /** * Validates the tool and its parameters */ export function validateToolRequest( toolId: string, tool: ToolConfig | undefined, params: Record ): void { if (!tool) { throw new Error(`Tool not found: ${toolId}`) } // Ensure all required parameters for tool call are provided for (const [paramName, paramConfig] of Object.entries(tool.params)) { if (paramConfig.requiredForToolCall && !(paramName in params)) { throw new Error(`Parameter "${paramName}" is required for ${toolId} but was not provided`) } } }