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>
81 lines
4.0 KiB
Markdown
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.
|