import { CloseBotClient, err } from "../client.js"; import type { ToolDefinition, ToolResult, LeadDto, LeadDtoPaginated } from "../types.js"; export const tools: ToolDefinition[] = [ { name: "lead_manager_app", description: "Searchable lead table with fields, conversation snippets, and status indicators. Returns HTML visualization.", inputSchema: { type: "object", properties: { sourceId: { type: "string", description: "Filter by source ID" }, page: { type: "number", description: "Page number (0-indexed)" }, pageSize: { type: "number", description: "Page size (default 20, max 100)" }, leadId: { type: "string", description: "Show details for a specific lead" }, }, }, }, ]; function escapeHtml(s: string): string { return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function renderLeadTable(data: LeadDtoPaginated): string { const leads = data.results || []; const rows = leads .map((lead) => { const lastMsg = lead.lastMessage ? escapeHtml(lead.lastMessage.slice(0, 50)) : ''; const direction = lead.lastMessageDirection === "outbound" ? '→ out' : lead.lastMessageDirection === "inbound" ? '← in' : ''; const time = lead.lastMessageTime ? new Date(lead.lastMessageTime).toLocaleString() : "—"; const source = lead.source?.name || "—"; const fieldCount = lead.fields?.length || 0; const instanceCount = lead.instances?.length || 0; const failReason = lead.mostRecentFailureReason ? `
⚠️ ${escapeHtml(lead.mostRecentFailureReason.slice(0, 40))}
` : ""; const tags = lead.tags && lead.tags.length > 0 ? lead.tags .slice(0, 3) .map((t) => `${escapeHtml(t)}`) .join(" ") : ""; return `
${escapeHtml(lead.name || "Unknown")}
${escapeHtml(lead.id || "")}
${tags ? `
${tags}
` : ""} ${escapeHtml(source)} ${direction}
${lastMsg}
${failReason} ${escapeHtml(time)} ${fieldCount} ${instanceCount} `; }) .join(""); return `

👥 Lead Manager

${data.total ?? leads.length} total leads · Page ${(data.page ?? 0) + 1} · ${data.pageSize ?? 20} per page
${rows || ''}
Lead Source Last Message Time Fields Bots
No leads found
`; } function renderLeadDetail(lead: LeadDto): string { const fields = (lead.fields || []) .map( (f) => `${escapeHtml(f.field || "")}${escapeHtml(f.value || "—")}` ) .join(""); const instances = (lead.instances || []) .map( (i) => `${escapeHtml(i.botId || "")}v${escapeHtml(i.botVersion || "?")}${i.followUpTime ? new Date(i.followUpTime).toLocaleString() : "—"}` ) .join(""); const tags = (lead.tags || []) .map((t) => `${escapeHtml(t)}`) .join(""); return `

👤 ${escapeHtml(lead.name || "Unknown Lead")}

${escapeHtml(lead.id || "")}
Source
${escapeHtml(lead.source?.name || "—")}
Last Message
${escapeHtml((lead.lastMessage || "—").slice(0, 80))}
Contact ID
${escapeHtml(lead.contactId || "—")}
${tags ? `
${tags}
` : ""} ${lead.mostRecentFailureReason ? `
⚠️ ${escapeHtml(lead.mostRecentFailureReason)}
` : ""}

📋 Fields (${lead.fields?.length || 0})

${fields || ''}
No fields

🤖 Bot Instances (${lead.instances?.length || 0})

${instances || ''}
Bot IDVersionFollow-up
No instances
`; } export async function handler( client: CloseBotClient, name: string, args: Record ): Promise { try { if (args.leadId) { const lead = await client.get(`/lead/${args.leadId}`); const html = renderLeadDetail(lead); return { content: [{ type: "text", text: `Lead details: ${lead.name || lead.id}` }], structuredContent: { type: "html", html }, }; } const data = await client.get("/lead", { page: args.page, pageSize: args.pageSize || 20, sourceId: args.sourceId, }); const html = renderLeadTable(data); return { content: [{ type: "text", text: `${data.total ?? (data.results?.length || 0)} leads found` }], structuredContent: { type: "html", html }, }; } catch (error) { return err(error); } }