import { z } from 'zod';
import { FinixContext, ToolFactory, SearchResult } from '../../types.js';
import { FinixClient } from '../../utils/finixClient.js';
const searchDocsPrompt = (context: FinixContext = {}) => `
This tool searches the Finix documentation for relevant information.
It takes the following arguments:
- query (str): The search query to find relevant Finix documentation.
- limit (int, optional): Maximum number of results to return (default: 10).
- category (str, optional): Filter by document category - "api" for API Reference, "docs" for Documentation, or "all" for both (default: "all").
`;
const searchDocsParameters = (context: FinixContext = {}) => z.object({
query: z.string().describe('The search query to find relevant Finix documentation'),
limit: z.number().int().min(1).max(50).optional().default(10).describe('Maximum number of results to return'),
category: z.enum(['api', 'docs', 'all']).optional().default('all').describe('Filter by document category')
});
const searchDocsAnnotations = () => ({
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
readOnlyHint: true,
title: 'Search Finix Documentation'
});
const searchDocs = async (client: FinixClient, context: FinixContext, params: any): Promise<any> => {
try {
const { query, limit = 10, category = 'all' } = params;
// Build filters based on category selection
const filters: any[] = [];
if (category === 'api') {
filters.push({
field: 'redocly_category',
values: ['API Reference'],
isQuickFilter: true
});
} else if (category === 'docs') {
filters.push({
field: 'redocly_category',
values: ['Documentation'],
isQuickFilter: true
});
} else if (category === 'all') {
filters.push({
field: 'redocly_category',
values: ['API Reference', 'Documentation'],
isQuickFilter: true
});
}
const response = await client.searchDocs(query, filters);
if (response.error) {
return `Error searching Finix docs: ${response.error.message}`;
}
const results = parseSearchResults(response.data, limit);
return formatSearchResults(results, query);
} catch (error) {
return `Error searching Finix docs: ${error instanceof Error ? error.message : 'Unknown error'}`;
}
};
function parseSearchResults(data: any, limit: number): SearchResult[] {
if (!data || !data.documents) {
return [];
}
const results: SearchResult[] = [];
// Process API Reference documents
if (data.documents['API Reference'] && Array.isArray(data.documents['API Reference'])) {
const apiDocs = data.documents['API Reference'].slice(0, limit);
for (const item of apiDocs) {
if (item.document) {
const doc = item.document;
const title = `${doc.httpMethod?.toUpperCase() || 'API'} ${doc.httpPath || doc.apiTitle || 'Finix API'}`;
const deepLink = doc.parameters?.[0]?.deepLink || '';
const baseUrl = 'https://docs.finix.com/api';
const url = deepLink ? `${baseUrl}${deepLink}` : baseUrl;
// Create snippet from parameters descriptions
let snippet = doc.apiTitle || 'Finix API documentation';
if (doc.parameters && doc.parameters.length > 0) {
const paramDesc = doc.parameters
.filter((p: any) => p.description)
.slice(0, 2)
.map((p: any) => p.description)
.join('. ');
if (paramDesc) {
snippet = paramDesc.substring(0, 200);
}
}
results.push({
title,
url,
snippet,
score: item.score
});
}
}
}
// Process Documentation documents if present
if (data.documents['Documentation'] && Array.isArray(data.documents['Documentation'])) {
const remainingLimit = limit - results.length;
const docs = data.documents['Documentation'].slice(0, remainingLimit);
for (const item of docs) {
if (item.document) {
const doc = item.document;
results.push({
title: doc.title || 'Finix Documentation',
url: doc.url || 'https://docs.finix.com',
snippet: doc.description || doc.snippet || 'Finix documentation page',
score: item.score
});
}
}
}
return results;
}
function formatSearchResults(results: SearchResult[], query: string): string {
if (results.length === 0) {
return `No results found for "${query}"`;
}
let formatted = `Found ${results.length} result(s) for "${query}":\n\n`;
results.forEach((result, index) => {
formatted += `${index + 1}. **${result.title}**\n`;
formatted += ` URL: ${result.url}\n`;
if (result.snippet) {
formatted += ` ${result.snippet}\n`;
}
if (result.score !== undefined) {
formatted += ` Relevance: ${(result.score * 100).toFixed(1)}%\n`;
}
formatted += '\n';
});
return formatted;
}
const tool: ToolFactory = (context) => ({
method: 'search_finix_docs',
name: 'Search Finix Documentation',
description: searchDocsPrompt(context),
parameters: searchDocsParameters(context),
annotations: searchDocsAnnotations(),
actions: {
documentation: {
read: true
}
},
execute: searchDocs
});
export default tool;