Hardcode is_incognito: true in the Perplexity request and remove the toggle surface: the incognito tool parameter, PI_PERPLEXITY_INCOGNITO env var, config file field, /perplexity-config prompt, and TUI status indicators. Config and resolveDefaultModel are now model-only. Supersedes the incognito portion of PR #4. Co-authored-by: Ivan Pereira <183991+ivanrvpereira@users.noreply.github.com>
4.0 KiB
4.0 KiB
pi-perplexity
Stack
- TypeScript extension for
@earendil-works/pi-coding-agent; loaded directly via jiti, no build artifact. - Node >=18.14.1 runtime APIs only:
fetch,crypto.randomUUID(),Buffer.from(..., "base64url"),Intl. - Pi-bundled packages live in
peerDependencieswith"*":@earendil-works/pi-tui,@earendil-works/pi-ai.Typeis re-exported by@earendil-works/pi-ai; do not depend ontypeboxdirectly.
Commands
npm run typecheck
npm test
node --no-deprecation --import ./node_modules/@earendil-works/pi-coding-agent/node_modules/jiti/lib/jiti-register.mjs --input-type=module -e "import('./src/index.ts').then((m)=>{ const entry = m.default?.default ?? m.default; if (typeof entry !== 'function') throw new Error('default export missing'); })"
File-Scoped Commands
| Task | Command |
|---|---|
| Single test file | npm run test:build && node --test --experimental-test-module-mocks ".tmp-test/test/search/stream.test.js" |
| Live E2E opt-in | PI_PERPLEXITY_E2E=1 npm test |
Structure
src/index.ts— extension entry andperplexity_searchtool definition.src/auth/— JWT extraction, email OTP login, token storage.src/search/— Perplexity SSE request, stream merge, result formatting, models.src/render/— TUI renderers for tool calls and results.src/commands/— slash commands such as login/config.test/— automated Node test suite;.tmp-test/is generated bynpm run test:build.local_tests/— manual/debug scripts and captured dumps; do not treat as automated coverage.docs/design-decisions.md— rationale for non-obvious behavior.
Extension Conventions
- Entry point exports a default factory from
src/index.ts. - Tool name is
perplexity_search. - Tool
executesignature is(toolCallId, params, signal, onUpdate, ctx). - Tool results use
{ content: [{ type: "text", text }], details: { ... } }. - String enum params use
StringEnumfrom@earendil-works/pi-ai;Type.Union([Type.Literal(...)])breaks Google models. - Stream/API types stay loose: all reverse-engineered event fields are optional.
Perplexity Protocol Gotchas
- Endpoint:
POST https://www.perplexity.ai/rest/sse/perplexity_ask. - Required Perplexity constants live in
src/constants.ts. - Searches always send
is_incognito: trueto avoid polluting user history; there is no toggle. - The response is
data:JSON lines with[DONE], not a fully standard SSE stream. - Events are incremental snapshots: shallow-merge top level, merge blocks by
intended_usage, splice markdown viachunk_starting_offset, accumulate sources. - Completion is
event.final === trueorevent.status === "COMPLETED". - Answer extraction order: markdown blocks →
ask_textblocks → event text. - Source extraction order:
web_resultsblock →sources_list; deduplicate by URL.
Auth Gotchas
- Auth tries macOS app token first via
defaults read ai.perplexity.mac authToken, unlessPI_AUTH_NO_BORROW=1. - Email OTP fallback uses
ctx.ui.input(). - Tokens are stored at
~/.config/pi-perplexity/auth.jsonwith mode0600. - Stored tokens have no expiry tracking;
loadToken()returns any cached token and expiry surfaces as 401/403 at request time. - AUTH errors preserve the cached token; users explicitly clear/re-auth with
/perplexity-login --force.
Boundaries
Always
- Pass
AbortSignalthrough to network calls. - Return user-readable error text from tool execution instead of throwing raw errors.
- Keep runtime dependency-free; use platform APIs for HTTP, SSE parsing, JWT decoding, and UUIDs.
Ask First
- Changing Perplexity request headers, model IDs, or auth flow behavior.
- Adding package dependencies or generated build artifacts.
- Deleting captured local test dumps or token-related files.
Never
- Never commit secrets, credentials,
.env, cached auth tokens, or live Perplexity response dumps containing private data. - Never clear cached auth automatically on transient 401/403 responses.