import { rawFunctionTool, type ToolsProviderController } from "@lmstudio/sdk";
import { openAIDocs, type DocEntry } from "./docs/openai";
import { anthropicDocs } from "./docs/anthropic";
import { minimaxDocs } from "./docs/minimax";
import { geminiDocs } from "./docs/gemini";
import { mistralDocs } from "./docs/mistral";
import { cohereDocs } from "./docs/cohere";
import { groqDocs } from "./docs/groq";
import { togetherDocs } from "./docs/together";
import { deepseekDocs } from "./docs/deepseek";
import { perplexityDocs } from "./docs/perplexity";
import { xaiDocs } from "./docs/xai";
import { searchDocsRAG } from "./ragSearch";
const ALL_DOCS: DocEntry[] = [
...openAIDocs,
...anthropicDocs,
...minimaxDocs,
...geminiDocs,
...mistralDocs,
...cohereDocs,
...groqDocs,
...togetherDocs,
...deepseekDocs,
...perplexityDocs,
...xaiDocs,
];
const PROVIDER_NAMES: Record<string, string> = {
openai: "OpenAI (ChatGPT)",
anthropic: "Anthropic (Claude)",
minimax: "MiniMax",
gemini: "Google Gemini",
mistral: "Mistral AI",
cohere: "Cohere",
groq: "Groq",
together: "Together AI",
deepseek: "DeepSeek",
perplexity: "Perplexity",
xai: "xAI (Grok)",
};
function scoreDoc(doc: DocEntry, query: string): number {
const q = query.toLowerCase();
const words = q.split(/\s+/).filter(w => w.length > 1);
let score = 0;
const titleLower = doc.title.toLowerCase();
const contentLower = doc.content.toLowerCase();
const providerLower = doc.provider.toLowerCase();
for (const word of words) {
if (titleLower.includes(word)) score += 10;
if (providerLower.includes(word)) score += 8;
for (const kw of doc.keywords) {
if (kw.toLowerCase().includes(word)) score += 5;
}
const regex = new RegExp(word, "gi");
const matches = contentLower.match(regex);
if (matches) score += matches.length;
}
if (contentLower.includes(q)) score += 20;
if (titleLower.includes(q)) score += 15;
return score;
}
function searchDocs(query: string, provider?: string, category?: string): string {
return searchDocsRAG(ALL_DOCS, query, provider, category, 5);
}
function listProviders(): string {
let result = "## Available API Documentation Providers\n\n";
const providers = new Map<string, DocEntry[]>();
for (const doc of ALL_DOCS) {
if (!providers.has(doc.provider)) {
providers.set(doc.provider, []);
}
providers.get(doc.provider)!.push(doc);
}
for (const [provider, docs] of providers) {
result += `### ${PROVIDER_NAMES[provider] || provider}\n`;
for (const doc of docs) {
result += `- **${doc.title}** (category: ${doc.category})\n`;
}
result += "\n";
}
result += "## Usage\n";
result += 'Use `api_docs_search` tool with:\n';
result += '- query: what you are looking for (required)\n';
result += '- provider: filter by provider name (optional)\n';
result += '- category: filter by category (optional)\n\n';
result += "## Categories\n";
result += "- **chat**: Chat/completions endpoints\n";
result += "- **tools**: Function calling / tool use\n";
result += "- **embeddings**: Vector embeddings\n";
result += "- **multimodal**: Image/audio/video input\n";
result += "- **output**: Structured output, JSON mode\n";
result += "- **limits**: Rate limits, pricing\n";
result += "- **optimization**: Caching, performance\n";
result += "- **rerank**: Document reranking\n";
result += "- **completion**: Text completion\n";
return result;
}
export async function toolsProvider(ctl: ToolsProviderController): Promise<any[]> {
const tools = [];
tools.push(rawFunctionTool({
name: "api_docs_search",
description: `
Search AI API documentation for coding references.
USE THIS TOOL when:
- Writing code that calls AI APIs (OpenAI, Claude, Gemini, etc.)
- Need to check API parameters, endpoints, or request formats
- User asks about how to use a specific AI API
- Need to verify correct syntax for function calling, embeddings, etc.
DO NOT hallucinate API details - search this tool instead.
Parameters:
- query: what you are searching for (required)
- provider: filter by provider - "openai", "anthropic", "minimax", "gemini", "mistral", "cohere", "groq", "together", "deepseek", "perplexity", "xai" (optional)
- category: filter by category - "chat", "tools", "embeddings", "multimodal", "output", "limits" (optional)
`,
parametersJsonSchema: {
type: "object",
properties: {
query: { type: "string", description: "What to search for in the documentation" },
provider: { type: "string", description: "Filter by provider: openai, anthropic, minimax, gemini, mistral, cohere, groq, together, deepseek, perplexity, xai" },
category: { type: "string", description: "Filter by category: chat, tools, embeddings, multimodal, output, limits" }
},
required: ["query"]
},
implementation: async (params: Record<string, unknown>) => {
const query = String(params.query || "").trim();
const provider = params.provider ? String(params.provider).trim() : undefined;
const category = params.category ? String(params.category).trim() : undefined;
if (!query) return "Please provide a search query";
return searchDocs(query, provider, category);
},
}));
tools.push(rawFunctionTool({
name: "api_docs_list",
description: `
List all available API documentation providers and their topics.
USE THIS TOOL to see what documentation is available before searching.
`,
parametersJsonSchema: {
type: "object",
properties: {},
required: []
},
implementation: async () => {
return listProviders();
},
}));
return tools;
}