Perplexed 0.2.1 — deep research that actually keeps the research
Run a directory template with sonar-deep-research and you'd get a near-empty note — the streaming reader was taking the wrong field and discarding ~99% of every response before it reached the file. 0.2.1 fixes that, keeps the citations even when a long research stream drops mid-flight, adds a per-run model picker to the run dialog, and rebuilds the toolkit-profile template so the model searches the product's real name and triages SEO slop instead of citing it.
Why care?
If you generate research notes in Obsidian with Perplexed's directory templates — the "Apply directory template to current file" workflow that fills a Tooling/ or concept file from a heading skeleton — 0.2.1 is the release where the deep-research path actually works.
The headline fix: sonar-deep-research runs now keep their output. Perplexity's deep-research model does all its work server-side, then delivers the entire finished document — often 10,000+ characters — in the first event of its streaming response, inside a field the plugin wasn't reading. The streaming reader took delta.content, which is correct for the lighter sonar models that stream token-by-token, and on a deep-research response that field holds only a ~75-character tail fragment of a 10,000-character report. The other 99% arrived on the wire and was thrown away. If you ever ran a directory template on the deep-research model and got a near-empty note, that was this bug — and toolkit-profile shipped with sonar-deep-research as its default model, so it was the default that was broken. Fixed.
Citations survive a dropped connection. Deep research can hold a stream open for minutes; a WiFi roam or an idle socket mid-stream used to discard everything — including the citations, which deep research delivers up front in that same first event. A cut-off run now keeps whatever content and sources already arrived, writes the citations footer anyway, and tells you it was truncated so you can re-run for the rest.
You pick the model when you run, not in a file you have to remember to edit. "Apply directory template" now opens a run dialog with a model dropdown. And the loading toast finally names the model that's actually running, instead of the hardcoded "deep research" string it had been showing regardless.
What's new?
Deep-research streaming — read the snapshot, not the fragment
Both streaming paths (the directory-template runner and the modal "Ask Perplexity" command) now treat Perplexity's cumulative message.content snapshot as the source of truth, diff it against what's already been written, and append only the new tail. This is correct for every model:
| Model | How it streams | Old reader (delta.content only) | 0.2.1 reader (message.content snapshot) |
sonar, sonar-pro | Token-by-token deltas | Worked | Works |
sonar-deep-research | Whole document in event 1, then tiny deltas | Captured ~75 of ~10,234 chars | Captures the full document |
A startsWith guard means a prefix that ever changes is skipped rather than corrupting the note — Perplexity's stream is append-only in practice, but the reader doesn't assume it.
Citations that survive a timeout
streamPerplexityToFile no longer throws away a run when the socket drops. It catches the read error, returns whatever streamed / sources / images it has, and flags the run truncated. applyTemplate then writes the partial content with its sources footer and shows a notice — "stream cut off … saved partial content with N sources. Re-run to complete." The modal path got the same treatment: its catch block now salvages the citation metadata it already received before writing the error line.
The deep-research idle timeout was also lengthened — 90s → 270s in the modal path, since deep research legitimately holds the socket silent for minutes while it researches server-side; 90s was firing on healthy runs.
A model picker in the run dialog
"Apply directory template to current file" used to be a bare fuzzy template picker. It now opens DirectoryTemplateRunModal: a template dropdown (when more than one template matches the file), a model dropdown — sonar-pro, sonar-reasoning-pro, sonar, sonar-reasoning, sonar-deep-research — and Run / Cancel. The model defaults to the template's cft model: and overrides it for that run only; the template file is never touched. The cf_last_run_model frontmatter stamp now records the model that actually ran, override included.
Domain scoping — cf_search_domains
New search_domain_filter support. A target file can carry a cf_search_domains: list in its frontmatter (entity-specific), and a template can carry a search-domains: key in its cft block (generic). Plain entries allowlist, a leading - denylists, capped at Perplexity's 10-domain limit. Job boards — Indeed, Glassdoor, ZipRecruiter, USAJobs — are denied on every run automatically, since a job listing is never a product source.
Allowlisting is positioned as a last resort, not the workflow: hand-curating domains is the same labour as searching yourself. It's there for names so collision-prone that nothing else recovers them — NATS the messaging system versus NATS the UK air traffic authority being the canonical case.
The toolkit-profile template, rebuilt
The shipped toolkit-profile template got a full system-prompt overhaul, because the old one was quietly steering the model wrong:
Anchored on the real name, not the scraped tagline. The prompt used
{{title}}as the entity identity — but in scraped Tooling filestitleis the page'sog:title, a marketing tagline. ProfilingKubernetes.mdtold the model the entity was named "Production-Grade Container Orchestration," so it searched the tagline. The prompt now anchors on{{basename}}(the filename = the real name) and explicitly flags{{title}}as a tagline.Source-quality is a triage task, not an allow/deny list. The old prompt hard-banned "consulting vendors." The new one tells the model it's the editor: search rankings are SEO-driven, so judge each page on its merits — favour editorial authority (the entity's own docs, standards bodies, established trade press) over rank, and treat a vendor's blog post as fine if the page itself is substantive. The only hard reject is a page about a different same-named entity.
"Search, don't recall." An explicit instruction that training knowledge is stale and uncitable, and that a profile assembled from memory rather than search results is a failed profile.
Length discipline. A
LENGTH AND ECONOMYblock turns the per-section sentence/paragraph counts already in the skeleton into hard ceilings, bans filler, and tells the model a thin section should be short — "length is not evidence of quality."Default model is now
sonar-pro— fast, clean, grounded — withsonar-deep-researcha dialog click away when you want depth.
Longer request timeout
The directory-template request timeout default moved from 5 minutes to 10 (DEFAULT_SETTINGS in main.ts), so a sonar-deep-research run picked from the model dialog has room to finish.
Under the hood
0.2.1 is a single concentrated session of work — there are no intermediate commits between the 0.2.0 release and this one. The changeset, eight files:
| File | Change |
src/services/perplexityService.ts | message.content-snapshot streaming; metadata salvage in the catch block; deep-research idle timeout 90s → 270s |
src/services/directoryTemplateService.ts | Same streaming fix; truncated partial-result salvage; search_domain_filter support (cf_search_domains + search-domains + job-board denylist); per-run model override |
src/modals/DirectoryTemplateRunModal.ts (new) | The template + model run dialog |
main.ts | Run-modal wiring; 10-minute timeout default |
src/docs/templates/toolkit-profile.md | Rebuilt system prompt — entity anchoring, source triage, concision, sonar-pro default |
manifest.json, package.json, versions.json | 0.2.1; description aligned ("Perplexica (now Vane)") |
The streaming bug was found the honest way — a raw curl against sonar-deep-research with stream: true, watching the SSE events scroll past. Event one carried a 10,169-character message.content and a 10-character delta.content. That was the whole diagnosis.
What's next
Validate the rebuilt template on clean runs. The
toolkit-profileoverhaul ships in this release; the next pass confirms entity-anchoring and source-triage hold up across a spread ofTooling/entries.Carry the prompt rebuild to the other three templates.
concept-profile,vocabulary-profile, andsource-profilestill use the old prompt shape and likely mis-anchor the same way. The entity-name fix and the triage instruction generalize directly.A
max-tokensceiling. If prompt-level concision isn't enough to rein in deep research, amax-tokens:cftkey would give a hard cap — held back here because a hard cap truncates mid-sentence and prompt discipline is the cleaner lever.Diff-aware regeneration. Still true from 0.2.0's list: a re-run on a file that already has
cf_last_runstamped should offer to replace rather than silently append. Right now stacked re-runs pile up.
References
Release on GitHub: https://github.com/lossless-group/perplexed-plugin/releases/tag/0.2.1
Install from Obsidian: Settings → Community Plugins → Browse → "Perplexed"
Prior release:
0.2.0— Google Gemini joins the provider lineupPerplexity models: docs.perplexity.ai —
sonar,sonar-pro,sonar-reasoning-pro,sonar-deep-research