Forked from bakit/ai-to-pdf
src / toolsProvider.ts
import { tool, Tool, ToolsProviderController } from "@lmstudio/sdk";
import { z } from "zod";
import fsp from "fs/promises";
import { join } from "path";
import fs from "fs";
export async function toolsProvider(ctl: ToolsProviderController): Promise<Tool[]> {
const tools: Tool[] = [];
const pdfTool = tool({
name: "Generate PDF",
description: "Convert Markdown to PDF using Puppeteer. Supports all languages, tables, code blocks, etc.",
parameters: {
text: z.string().describe("Markdown text content to include in the PDF"),
filename: z.string().optional().describe("Optional filename for the PDF"),
},
implementation: async ({ text, filename }, { status, warn }) => {
try {
status("Generating PDF...");
// Dynamic import of marked (ESM)
const { marked } = await import("marked");
// Dynamic import of puppeteer
const puppeteer = await import("puppeteer");
const workingDir = ctl.getWorkingDirectory();
await fsp.mkdir(workingDir, { recursive: true });
const timestamp = Date.now();
const pdfName = filename || `ai-output-${timestamp}.pdf`;
const pdfPath = join(workingDir, pdfName);
// Convert Markdown to HTML
const htmlContent = `
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: "Arial Unicode MS", "Segoe UI", "Noto Sans", sans-serif; padding: 40px; }
table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }
th, td { border: 1px solid #333; padding: 6px; text-align: left; }
pre { background: #f0f0f0; padding: 8px; overflow-x: auto; }
blockquote { color: gray; margin-left: 20px; border-left: 3px solid #ccc; padding-left: 10px; }
</style>
</head>
<body>
${marked(text)}
</body>
</html>
`;
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
const page = await browser.newPage();
await page.setContent(htmlContent, { waitUntil: 'networkidle0' });
await page.pdf({
path: pdfPath,
format: 'A4',
printBackground: true,
margin: { top: '40px', bottom: '40px', left: '40px', right: '40px' }
});
await browser.close();
status(`PDF saved as ${pdfName}`);
return { filename: pdfName, path: pdfPath };
} catch (err: any) {
console.error("PDF generation failed:", err);
warn(`Failed to generate PDF: ${err?.message ?? String(err)}`);
return { error: err?.message ?? String(err) };
}
}
});
tools.push(pdfTool);
return tools;
}