enne2 e007109ca9
CI / test (push) Canceled after 0s
feat(auth): validate credentials with the persisted GraphQL query
Verified 2026-10-11: POST /rest/perplexity_ask/graphql with the persisted
read-only query LibraryThreadsRelayQuery answers 401 'Authentication required'
for a dead credential (or a browser cookie) and 200 with data for a live OTP
Bearer. Unlike /api/auth/session ({} for dead credentials, ambiguous) it is
unambiguous, and unlike the incognito query probe it consumes no query and adds
nothing to the account.

- probe.ts: probeGraphql() is now the primary probe in probeCredential();
  probeSession() and probeWithAsk() remain as fallbacks when it is inconclusive.
  ask:false still stops before the query-costing probe.
- tests: GraphQL probe mapping (200/401/500/error payload), request shape
  (persisted query hash, Bearer header), and probeCredential ordering
- README/AGENTS/CHANGELOG: document the auth model (Bearer-only; browser cookies
  are rejected by the API) and the new probe

Measured on the live credential: valid in ~340 ms, no query consumed.
2026-10-11 01:32:08 +02:00
2026-02-16 18:42:03 +00:00
2026-07-16 16:01:38 +01:00
2026-07-16 16:01:38 +01:00
2026-07-14 12:42:56 +01:00

pi-perplexity

A pi extension that gives your coding agent real-time web search powered by your Perplexity Pro or Max subscription

Requirements

  • pi coding agent with its bundled Node runtime (Node 18.14.1+ if running outside pi)
  • A Perplexity Pro or Max subscription
  • macOS (for zero-interaction auth), an interactive terminal (for email OTP), or a signed-in browser session cookie/token

Installation

pi install npm:pi-perplexity

Or from GitHub:

pi install github:ivanrvpereira/pi-perplexity

Authentication

Run login once:

/perplexity-login

This usually reuses an existing cached login, borrows the Perplexity macOS app login if available, or asks for your email OTP code.

The email is asked only once: after a successful OTP login it is remembered in ~/.config/pi-perplexity/profile.json (mode 0600, email only, no credentials), which survives /perplexity-login --force. To sign in with a different account, pass it explicitly:

/perplexity-login --force --email other@example.com

On Linux the macOS desktop-app token is never available, so email OTP (or browser login) is the path used there.

If login fails with a Cloudflare “Just a moment...” page, use browser login instead:

/perplexity-login --browser

Browser login

Use this on Linux/headless machines when direct OTP is blocked.

  1. Open https://www.perplexity.ai and sign in.
  2. Open browser DevTools → Network.
  3. Reload the page, or ask one Perplexity question.
  4. Right-click a www.perplexity.ai request, preferably perplexity_ask.
  5. Choose Copy → Copy as cURL.
  6. Paste the copied cURL command into the pi prompt.

The copied text must include cookies. A good copy contains one of -b, --cookie, or Cookie:, and should include __Secure-next-auth.session-token. If it does not, copy a different request.

You can also paste just the request Cookie: header, or just the __Secure-next-auth.session-token cookie value. Full cURL is recommended because it also includes Cloudflare cookies like cf_clearance.

The token is saved to ~/.config/pi-perplexity/auth.json (mode 0600) and reused across sessions. On auth failure, run /perplexity-login --force to clear and re-authenticate; the remembered email is kept in profile.json, so the login flow does not ask for it again.

Session lifetime and renewal

Perplexity sessions last about 30 days, and there is no refresh-token grant: an expired credential cannot be renewed, only replaced. When the stored session dies, a search is answered with a login wall (HTTP 200, body Sign up and repeat your request.) instead of a 401/403, which the extension reports as an AUTH error.

Browser cookies do not help (verified 2026-10-11). With a live, freshly rotated Firefox session — the browser was signed in and able to search — replaying the cookies from outside the browser was rejected: /api/auth/session answered {} and perplexity_ask answered the login wall. That held with the session cookie alone, with the full cookie set (cf_clearance, __cf_bm, __cflb, pplx.session-id, …), with Chrome and Firefox user agents, and even with a browser-matching TLS fingerprint (curl_cffi impersonate="chrome131"/"firefox133"). The API appears to accept only the app-issued Bearer credential from the OTP flow.

Consequences:

  • /perplexity-login --force (email + OTP) is the only working renewal path, needed at most once per ~30 days. The email is remembered, so only the OTP code is required.
  • The Firefox-cookie channel still exists in the code (src/auth/browser-cookies.ts, src/auth/renew.ts) but is opt-in and off by default: set PI_PERPLEXITY_BROWSER_RENEW=1 to let the automatic paths try it. /perplexity-status --renew attempts it explicitly regardless.
  • A candidate cookie is always probed before being written, so a stale browser cookie — browsers keep session cookies long after the server-side session is gone — is never stored. The probe is a persisted read-only GraphQL query (LibraryThreadsRelayQuery): 401 Authentication required means dead, 200 with data means live. It costs no query and nothing is added to the account; the session endpoint and a tiny incognito query are only fallbacks when the GraphQL probe is inconclusive.
  • /perplexity-status reports the credential type, validity, when it was obtained and the estimated expiry; a warning appears at startup after ~25 days.
/perplexity-status          # validity, when the credential was obtained, estimated expiry
/perplexity-status --renew  # try to adopt a live browser session (opt-in channel, not expected to work)
/perplexity-login --force   # email + OTP login: the only working path

Environment variables

Variable Description
PI_AUTH_NO_BORROW=1 Skip macOS desktop app extraction and go straight to email OTP
PI_PERPLEXITY_TOKEN Raw Perplexity session token/JWT/JWE copied from a browser or another machine
PI_PERPLEXITY_COOKIE / PI_PERPLEXITY_COOKIES Full Perplexity Cookie header copied from a signed-in browser
PI_PERPLEXITY_EMAIL Pre-fill the email prompt (takes precedence over the remembered profile email; useful for non-interactive setups)
PI_PERPLEXITY_OTP Pre-fill the OTP prompt
PI_PERPLEXITY_BROWSER_RENEW=1 Opt in to the browser-cookie renewal channel (verified ineffective against the API; off by default)

Usage

Once installed, the agent automatically calls perplexity_search whenever it needs current information. You can also ask it directly:

"Search Perplexity for the latest React 19 release notes"

Tool parameters

Parameter Type Required Description
query string ✅ The search query
recency string — Filter by age: hour · day · week · month · year
focus string — Perplexity Focus Mode (source domain): internet · academic · writing · wolfram · youtube · reddit · math · social · finance (default internet)
limit number — Max sources to include (1–50)

Focus Modes let the agent route the search to a specific knowledge source: academic → peer-reviewed/scholarly (PubMed, arXiv, Semantic Scholar), youtube → video transcripts, reddit → community/opinions, wolfram/math → computations, social → social platforms, finance → financial/SEC data, writing → model-only (no live search).

Model selection is configured globally with /perplexity-config or PI_PERPLEXITY_MODEL; it is not exposed as a tool parameter, so agent-generated tool calls cannot accidentally override your configured model.

Output format

The tool returns structured text the agent can reason over:

## Answer
React 19 introduces Actions, use() hook, and improved Server Components...

## Sources
3 sources
[1] React 19 Release Notes (1d ago)
    https://react.dev/blog/2024/12/05/react-19
    React 19 is now stable. This release includes Actions for async...

[2] What's New in React 19 (3d ago)
    https://vercel.com/blog/react-19
    A deep dive into the new primitives landing in React 19...

## Meta
Provider: perplexity (oauth)
Model: pplx_pro_upgraded

Queries always send is_incognito: true, so searches never appear in your Perplexity web history.

How It Works

The extension calls Perplexity's internal SSE endpoint (perplexity_ask) using your subscription credentials obtained from the macOS app, email OTP, or a browser-imported session. Responses stream as incremental events that are merged into a final result. Network calls use the Node runtime already provided by pi; no extra runtime is required. Email OTP auth requires Headers.getSetCookie() support so auth cookies are exposed reliably.

Development

npm install          # Install dev dependencies
npm test             # Run tests
npm run typecheck    # Type check

Optional live model-selection E2E test (requires cached auth from /perplexity-login):

PI_PERPLEXITY_E2E=1 npm test
PI_PERPLEXITY_E2E=1 PI_PERPLEXITY_E2E_MODELS=pplx_pro_upgraded,gpt54 npm test

License

MIT — see LICENSE for details.


Disclaimer

This project is intended for educational and demonstration purposes only. It reverse-engineers an undocumented internal endpoint and uses credentials borrowed from the Perplexity macOS desktop app. This likely violates Perplexity's Terms of Service. Use at your own risk — your account may be suspended. The author makes no warranties and accepts no liability for any consequences of its use.

S
Description
Fork di pi-perplexity (ivanrvpereira) con supporto ai Focus Modes di Perplexity
Readme MIT
423 KiB
Languages
TypeScript 100%