Perplexity
PerplexityAgentHttpLLMService answers with web search through Perplexity's Agent API, over the OpenAI Responses protocol.
Overview
Perplexity's Agent API answers with web search, using models from Perplexity and from other
providers (openai/..., anthropic/... and so on). It speaks the OpenAI Responses protocol over
HTTP.
PerplexityAgentHttpLLMService: anOpenAIResponsesHttpLLMServicesubclass with Perplexity's base URL, a default model, and Perplexity's own settings (preset,webSearch,maxSteps). Function calling, multi-turn context, token usage metrics andrunInferencework as they do with the OpenAI Responses services.
PerplexityLLMService is not ported
Upstream's PerplexityLLMService, for the Sonar chat completions API, is deprecated since
Pipecat 1.13.0, as Perplexity no longer supports that API. pipedog doesn't port it. Use
PerplexityAgentHttpLLMService.
Upstream page
Pipecat's documentation for the same service.
Source
packages/perplexity/src/llm.ts.
Perplexity docs
The Agent API, its presets and its models.
Installation
bun add @pipedog/perplexityIt depends on @pipedog/openai, which is installed with it.
import { PerplexityAgentHttpLLMService } from "@pipedog/perplexity/llm";Prerequisites
- A Perplexity account and an API key from Perplexity.
- Pass the key as
apiKey. The examples read it fromPERPLEXITY_API_KEY. If you leave it out, the OpenAI client falls back toOPENAI_API_KEY, as with the OpenAI Responses services, which is not a Perplexity key.
PerplexityAgentHttpLLMService
Configuration
Prop
Type
The other options (organization, project, defaultHeaders, serviceTier, retryOnTimeout,
retryTimeoutSecs) are OpenAIResponsesHttpLLMService's. See
OpenAI Responses.
| Base URL | https://api.perplexity.ai/v1 |
| Default model | openai/gpt-5.6-luna |
Settings
Runtime-updatable settings, passed as settings: new PerplexityAgentHttpLLMService.Settings({...})
(PerplexityAgentLLMSettings). They are the
OpenAI Responses settings, with these defaults and
additions:
| Setting | Type | Default | Description |
|---|---|---|---|
model | string | null | "openai/gpt-5.6-luna" | Model, as <provider>/<model>. With a preset, it replaces the preset's model; set it to null to use the preset's. |
preset | string | null | null | Perplexity preset, such as "fast", "low", "medium", "high" or "xhigh". It sets the model, its instructions, its search budget and how much it reasons. Sent as preset in the request body. |
webSearch | boolean | true | Offer the web_search tool on every request, alongside any tools from the context. A preset searches the web whatever this is set to. |
maxSteps | number | null | null | Maximum number of search and reasoning steps per response, sent as max_steps. null leaves Perplexity's default. |
reasoning | OpenAIResponsesReasoningConfig | null | null | Reasoning config (PerplexityAgentHttpLLMService.ReasoningConfig). See the default below. |
Every other setting (systemInstruction, temperature, topP, maxCompletionTokens, extra, ...)
keeps its OpenAI Responses default. The settings need a model, a preset, or both: the
constructor throws when they leave neither, and a settings update that leaves neither pushes an
error.
Usage
import { LLMUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { PerplexityAgentHttpLLMService } from "@pipedog/perplexity/llm";
const llm = new PerplexityAgentHttpLLMService({
apiKey: process.env.PERPLEXITY_API_KEY ?? "",
settings: new PerplexityAgentHttpLLMService.Settings({
systemInstruction: "You are a helpful assistant in a voice conversation. Keep replies short.",
}),
});Let a preset choose the model:
// The "high" preset chooses the model, its instructions, its search budget and its reasoning.
// `model: null` clears the default model, so the preset's own is used.
const thorough = new PerplexityAgentHttpLLMService({
apiKey: process.env.PERPLEXITY_API_KEY ?? "",
settings: new PerplexityAgentHttpLLMService.Settings({ preset: "high", model: null }),
});Pin a model, cap the search steps and set the reasoning effort yourself:
// Another provider's model, with web search capped at three steps and a set reasoning effort.
const pinned = new PerplexityAgentHttpLLMService({
apiKey: process.env.PERPLEXITY_API_KEY ?? "",
settings: new PerplexityAgentHttpLLMService.Settings({
model: "openai/gpt-5.5",
maxSteps: 3,
reasoning: new PerplexityAgentHttpLLMService.ReasoningConfig({ effort: "low" }),
}),
});Change settings mid-call with an LLMUpdateSettingsFrame. The next request uses them:
// Queue it on the worker, or push it from a processor upstream of the service.
const update = new LLMUpdateSettingsFrame({
delta: new PerplexityAgentHttpLLMService.Settings({ webSearch: false, maxSteps: 1 }),
});Notes
- Runs a response for each
LLMContextFrame, between anLLMFullResponseStartFrameand anLLMFullResponseEndFrame, and streams the reply asLLMTextFrames. Each turn sends the whole context, asOpenAIResponsesHttpLLMServicedoes. - When neither
presetnorreasoningis set, the service sends Perplexity's"fast"preset, its lowest-latency configuration, with your model in place of the preset's own, and logs it on the first request for each model. A preset orreasoningyou set (in the settings, or inextra) is sent as it is. SetuseProviderThinkingDefaultto send no default and run at Perplexity's. - Perplexity runs its web search on the server. The search shows up in the stream as a function call, which the service drops, so only your own functions are run.
- Answers can carry citation markers such as
[1]. Filter them out before TTS if you don't want them read aloud. - Anthropic models need
maxCompletionTokensset. - Tokens written to the prompt cache are reported as
cacheCreationInputTokensin token usage metrics. PerplexityLLMAdapter(@pipedog/perplexity/perplexity_adapter) is still exported, as upstream keeps it for the deprecated Sonar service, butPerplexityAgentHttpLLMServicedoesn't use it: its messages go through the OpenAI Responses adapter.
Runtime notes
| Runtime | Works | What it needs |
|---|---|---|
| Bun | ✅ yes | Nothing. |
| Node.js | ✅ yes | Nothing. |
| Deno | ✅ yes | Nothing. |
| Cloudflare Workers | ✅ yes | Nothing. |
Generated from pipecat.runtimes and pipecat.compat in packages/perplexity/package.json: ✅ means the compat smoke test passes on that runtime.
- The client is the official
openaiJS SDK (through@pipedog/openai), which talks throughfetch. It works on Bun, Node, Deno and Cloudflare Workers. - The JS SDK has no
extra_bodyrequest option, so the service's client merges the request'sextra_body(wherepresetandmax_stepsgo) into the request JSON. - Unit-tested on the requests it builds and on scripted event streams, not against Perplexity itself.
pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.
Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).