@polyweave/perplexity (1.0.6)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/perplexity@1.0.6"@polyweave/perplexity": "1.0.6"About this package
@polyweave/perplexity
Perplexity AI provider adapter for Polyweave — search-grounded chat with citations via the Sonar API.
Published as @polyweave/perplexity.
Synopsis
import { createPerplexityAdapter } from '@polyweave/perplexity';
import { createTextFrame, createFrameSink } from '@polyweave/core';
const adapter = createPerplexityAdapter({ apiKey: process.env.PERPLEXITY_API_KEY, model: 'sonar-pro' });
adapter.source.pipe(createFrameSink(function(frame) {
if (frame.type === 'TEXT') console.log(frame.content.text);
if (frame.type === 'RECEIPT') console.log('Cost:', frame.content.totalCost);
if (frame.type === 'ERROR') console.error(frame.content.message);
}));
adapter.sink.write(createTextFrame('What is the latest news about AI?'));
Install
npm install @polyweave/perplexity
Why
All Perplexity Sonar models are search-grounded by default — citations appear inline in output. This adapter surfaces that natively through Polyweave's pure push-stream frame protocol: streaming SSE chunks become TEXT frames, token usage becomes RECEIPT frames, tool calls become TOOL_CALL frames. No Promises. No async/await. The adapter handles multi-turn conversation, streaming, non-streaming batch, tool calling, vision input via IMAGE frames, budget enforcement, cost estimation via COST_CHECK, and progressive receipt emission during streams (every 50 tokens). Cost tracking uses the actual Perplexity pricing table.
API
createPerplexityAdapter(config)
Creates a Perplexity AI adapter that communicates through a push-stream frame duplex.
Signature
function createPerplexityAdapter(config?: {
apiKey?: string,
baseURL?: string,
model?: string,
budget?: number,
name?: string | null,
timeout?: number
}): IFrameDuplex
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
config.apiKey |
string |
No | process.env.PERPLEXITY_API_KEY |
Perplexity API key. If null/undefined, frames are buffered until set via setReady() or a PARAM frame with { key: 'apiKey', value: '<key>' }. |
config.baseURL |
string |
No | 'https://api.perplexity.ai' |
Base URL for the Perplexity API. |
config.model |
string |
No | 'sonar' |
Default model. Set initially as params.model, overridable via PARAM frames. Supported: sonar, sonar-pro, sonar-reasoning-pro, sonar-deep-research. |
config.budget |
number |
No | 0 |
Total spend budget cap in USD. 0 means unlimited. When totalSpent >= budget, further TEXT/IMAGE frames emit ERROR (BUDGET_EXCEEDED) + END and are discarded. |
config.name |
string |
No | null |
Node name for topology targeting. Exposed as duplex.name. |
config.timeout |
number |
No | 120000 |
HTTP request timeout in milliseconds. |
Return Value
Returns an IFrameDuplex with:
duplex.source— Push-source that emits TEXT, TOOL_CALL, RECEIPT, ERROR, END, COST, TOPOLOGY_REPORT, TOPOLOGY_COMPLETE frames.duplex.sink— Push-sink that accepts TEXT, IMAGE, PARAM, COST_CHECK, TOOL_RESULT, START, END, TOPOLOGY_SCAN, TOPOLOGY_REPORT, TOPOLOGY_COMPLETE, TEST_INJECT, TEST_SNAPSHOT frames.duplex.setReady(apiKey)— Sets the API key and flushes any buffered frames. Call after construction if noapiKeywas provided in config.duplex.name— Theconfig.namevalue (ornull).
Frame Protocol
| Inbound (sink) | Outbound (source) | Description |
|---|---|---|
TEXT |
TEXT, RECEIPT, END |
Sends chat completion. Emits streaming/batch TEXT chunks, final RECEIPT, and END. |
IMAGE |
TEXT, RECEIPT, END |
Sends chat completion with image content. Uses frame.content.url, frame.content.data, or frame.content.b64_json. The image mimeType defaults to 'image/png'. |
PARAM |
— | Sets internal parameter. See PARAM Keys below. If key === 'apiKey', calls setReady(value). If key === 'budget', updates budgetTotal. |
COST_CHECK |
COST, END |
Enters cost-check mode. Buffers subsequent frames, computes a cost estimate via @polyweave/costs, and emits a COST frame with the estimate. If maxBudget is exceeded in check, emits ERROR + END instead. |
TOOL_RESULT |
TEXT, RECEIPT, END |
Appends tool result to conversation and triggers a new chat request. |
TOPOLOGY_SCAN |
TOPOLOGY_REPORT |
Responds with topology report identifying this node as 'perplexity-adapter'. |
START, END |
— | Ignored (no-op). |
TOPOLOGY_REPORT, TOPOLOGY_COMPLETE |
TOPOLOGY_REPORT, TOPOLOGY_COMPLETE |
Passthrough forwarding if downstream sink exists. |
TEST_INJECT |
— | Writes each frame from frame.content.frames into the sink. |
TEST_SNAPSHOT |
TEST_SNAPSHOT |
Emits a test snapshot frame. |
PARAM Keys
| Key | Type | Description |
|---|---|---|
model |
string |
Model name override (e.g. 'sonar-pro') |
max_tokens |
number |
Maximum completion tokens |
temperature |
number |
Sampling temperature |
top_p |
number |
Nucleus sampling threshold |
stream |
boolean |
Enable SSE streaming (default true) |
system |
string |
System prompt prepended to messages |
tools |
array |
Tool/function definitions |
tool_choice |
string|object |
Tool selection strategy |
response_format |
object |
Structured output format (e.g. { type: 'json_object' }) |
search_recency_filter |
string |
Search recency filter ('day', 'week', 'month', 'year') |
search_domain_filter |
array |
Domain filter for search (e.g. ['nytimes.com']) |
budget |
number |
Runtime spend cap update |
apiKey |
string |
Runtime API key update (triggers setReady) |
Error Conditions
All errors are emitted as frames (not thrown), using ADAPTER_ERROR type unless otherwise noted:
| Condition | Error Message | Error Type | Side Effect |
|---|---|---|---|
| API key not set | — | — | Frames are buffered silently. No error emitted. Flushed when setReady() is called or apiKey PARAM arrives. |
Budget exceeded (totalSpent >= budgetTotal) |
'Budget exceeded' |
BUDGET_EXCEEDED |
Emits ERROR frame then END frame with metadata.error: true. Incoming frame is discarded. |
COST_CHECK estimate exceeds maxBudget |
'Estimated cost $X exceeds budget $Y' |
BUDGET_EXCEEDED |
Emits ERROR frame then END frame. Cost-check mode is reset. |
IMAGE frame without url, data, or b64_json |
'IMAGE frame requires url, data, or b64_json' |
ADAPTER_ERROR |
Emits ERROR then END. |
| HTTP response status >= 400 | Parsed error.message from JSON body, or 'HTTP <status>' |
ADAPTER_ERROR |
Emits ERROR then END. |
| HTTP request timeout | 'Request timeout' |
ADAPTER_ERROR |
Request is destroyed. Emits ERROR then END. |
| HTTP request error (network, DNS, etc.) | err.message from the error event |
ADAPTER_ERROR |
Emits ERROR then END. |
| JSON parse error on response body | 'Parse: <message>' |
ADAPTER_ERROR |
Emits ERROR then END. |
API error in stream SSE chunk (e.error) |
e.error.message or 'Stream error' |
ADAPTER_ERROR |
Emits ERROR then END. |
API error in batch response (r.error) |
r.error.message or 'API error' |
ADAPTER_ERROR |
Emits ERROR then END. |
| General exception in sink.write catch block | err.message |
ADAPTER_ERROR |
Emits ERROR then END. |
Tests
npm test
Covers:
- rigor.test.js — Property tests on
getModelCostandcalculateTokenCost: cost-object shape, non-negative totals, zero-input zero-cost, pricing-table parity (actual vs computed per model), monotonicity. - smoke.test.js — Adapter construction with defaults and config,
setReadymethod presence, PARAM frame acceptance. - streaming.test.js — Streaming response handling (present but not included in default
npm testcommand).
Requirements
- Node.js 22 or later.
- ESM only (
"type": "module"). - Peer dependencies:
@polyweave/core,@polyweave/costs.
See Also
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |
| @polyweave/costs | * |
| @polyweave/errors | * |