Files
97aab3e9b9 refactor(search): always send searches as incognito (#14)
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>
2026-07-16 15:28:02 +01:00

81 lines
4.0 KiB
Markdown

# 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 `peerDependencies` with `"*"`: `@earendil-works/pi-tui`, `@earendil-works/pi-ai`. `Type` is re-exported by `@earendil-works/pi-ai`; do not depend on `typebox` directly.
## Commands
```bash
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 and `perplexity_search` tool 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 by `npm 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 `execute` signature is `(toolCallId, params, signal, onUpdate, ctx)`.
- Tool results use `{ content: [{ type: "text", text }], details: { ... } }`.
- String enum params use `StringEnum` from `@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: true` to 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 via `chunk_starting_offset`, accumulate sources.
- Completion is `event.final === true` or `event.status === "COMPLETED"`.
- Answer extraction order: markdown blocks → `ask_text` blocks → event text.
- Source extraction order: `web_results` block → `sources_list`; deduplicate by URL.
## Auth Gotchas
- Auth tries macOS app token first via `defaults read ai.perplexity.mac authToken`, unless `PI_AUTH_NO_BORROW=1`.
- Email OTP fallback uses `ctx.ui.input()`.
- Tokens are stored at `~/.config/pi-perplexity/auth.json` with mode `0600`.
- 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 `AbortSignal` through 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.