Skip to main content
Glama
perplexity-client.ts3.42 kB
import { type ChatOptions, PerplexityResponse } from "./schemas.js"; import { stripThinkContent } from "./strip-think-content.js"; /** * Performs a chat completion by sending a request to the Perplexity API. * Filters out <think> blocks from reasoning models before returning content. * * @param {Array<{ role: string; content: string }>} messages - An array of message objects. * @param {ChatOptions} options - Options for the chat completion. * @returns {Promise<string>} The chat completion result content. * @throws Will throw an error if the API request fails. */ export async function performChatCompletion( messages: Array<{ role: string; content: string }>, options: ChatOptions, ): Promise<string> { const apiKey = process.env.PERPLEXITY_API_KEY; if (!apiKey) { throw new Error( "PERPLEXITY_API_KEY is not set. Please export it before calling performChatCompletion().", ); } const url = new URL("https://api.perplexity.ai/chat/completions"); const body = { model: options.model, messages: [{ role: "system", content: options.system }, ...messages], web_search_options: { search_context_size: options.searchContextSize }, }; let response; try { response = await fetch(url.toString(), { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify(body), }); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Network error while calling Perplexity API: ${message}`); } if (!response.ok) { let errorText; try { errorText = await response.text(); } catch { errorText = "Unable to parse error response"; } throw new Error( `Perplexity API error: ${response.status} ${response.statusText}\n${errorText}`, ); } let json: unknown; try { json = await response.json(); } catch (jsonError) { const message = jsonError instanceof Error ? jsonError.message : String(jsonError); throw new Error( `Failed to parse JSON response from Perplexity API: ${message}`, ); } const parsedResponse = PerplexityResponse.safeParse(json); let messageContent: string = parsedResponse.success ? (parsedResponse.data.choices?.[0]?.message?.content ?? "") : ""; // Filter out <think> blocks from reasoning models (e.g., sonar-reasoning-pro) // These blocks contain internal reasoning tokens that should not be exposed to MCP clients messageContent = stripThinkContent(messageContent); // Build final content and normalize whitespace consistently // Append Sources section by rendering all search_results in order. if (parsedResponse.success && parsedResponse.data.search_results) { const results = parsedResponse.data.search_results; if (results.length > 0) { const lines = results.map((sr, index) => { const index_ = index + 1; const dateSuffix = sr.date ? ` (${sr.date})` : ""; return `[${index_}] ${sr.title} — ${sr.url}${dateSuffix}`; }); messageContent = `${messageContent}\n\nSources:\n${lines.join("\n")}`; } } // Trim leading and trailing whitespace, then ensure one trailing newline messageContent = messageContent.trim(); // Ensure trailing newline in final response messageContent += "\n"; return messageContent; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jercik/perplexity-agent-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server