Skip to content

Commit f946973

Browse files
mpstatonclaude
andcommitted
feat(release): 0.3.0 — three analyst-grade templates for VC/PE/equities + four infrastructure fixes for deep-research reliability
0.3.0 turns Perplexed into a serious analyst tooling layer for Venture Capital, Private Equity, and equities-trading workflows. Three new directory templates produce 6-9K-word cited analyst drafts in a single Perplexity Deep Research run. Underneath them, four infrastructure fixes turn deep-research from a brittle "might work" workflow into something you can put real analyst time behind. The three new templates: market-map-profile (analyst memo for Known Category or Thesis-Driven maps), standards-and-specs-profile (open-spec profiles with five-way authority typing and three-tier adoption framing), market-category-profile (concept-folder reference card with three financial-stage tiers — Incumbents / Challengers / Innovators). The four infrastructure fixes: per-template request-timeout-ms wall-clock override (yesterday, pressure-relief valve), structural port of per-chunk idle-timeout discipline from the legacy modal flow into the directory-template flow (yesterday, structural fix), per-template max-tokens Perplexity output-budget override (today, fixes silent clean-truncation when finish_reason=length fires mid-template), and a strengthened mermaid-discipline partial plus new latex-discipline partial (today, fixes the 4-of-5 broken-Mermaid rate via paired BAD/GOOD examples and a six-item pre-emit self-check). New templates (src/docs/templates/): - market-map-profile.md — sonar-deep-research, request-timeout-ms 2400000 (40-min ceiling), max-tokens 24000. Anti-incumbent editorial stance. - standards-and-specs-profile.md — sonar-deep-research, request-timeout-ms 0 (idle-only safety), max-tokens 24000. Five-way authority typing, named editors, stewardship transitions, named critics. - market-category-profile.md — sonar-deep-research, request-timeout-ms 0, max-tokens 24000. Three-tier financial-stage framing, separate Why Now and What's Happening sections, Industry Coverage sub-grouped into Market Reports / Industry Articles / Financial News. Rendering-discipline partials (src/docs/partials/): - mermaid-discipline.md rewritten — paired BAD/GOOD examples throughout, the &amp; escape rule, explicit \n vs <br/> ban, six-item self-check before emit, simplify-rather-than-break ethos. Original ~250 tokens expanded to ~440. - latex-discipline.md new — Obsidian MathJax delimiters and \$ escaping in prose to avoid accidental inline-math spans. - concept-profile.md wired in {{include: latex-discipline}} alongside the existing {{include: mermaid-discipline}}, placed immediately after the "render a mermaid codefence here" instruction so the rules are in scope at the moment of generation. Streaming, timeout, and output-budget infrastructure (src/services/ directoryTemplateService.ts): - streamPerplexityToFile now races each reader.read() against a fresh per-chunk idle timer (270s deep-research, 90s normal — matches the legacy modal flow at perplexityService.ts:659). Closes the "Wall-clock-timeout cuts off long deep-research streams" issue. - request-timeout-ms cft override is now the optional absolute wall-clock ceiling (belt-and-suspenders backstop on top of the idle timer); explicit 0 disables. - max-tokens cft override added to buildPayload — passes through to Perplexity's max_tokens parameter; lifts the silent ~8K-token default ceiling that was clean-truncating thorough drafts via finish_reason: length. Documentation (README.md, docs/directory-templates.md): - README — new top-level section "For Venture Capital, Private Equity, and Equities-Trading Workflows" with a five-row table mapping each analyst workflow to the template that produces it. Directory Templates section updated to seven shipped templates plus the new per-template cft-block knobs. - docs/directory-templates.md — new "Per-template max-tokens override" section with the diagnostic table for distinguishing wall-clock-timeout truncation (mid-sentence cutoff, no sources footer) from max_tokens truncation (clean section-end, full sources footer). The diagnostic vocabulary that did not exist before this release. Seeding (src/services/templateSeederService.ts): - Registered all three new templates plus the new latex-discipline partial so they auto-seed into vaults on first plugin load and appear in Re-seed runs. Version bump (manifest.json, package.json, versions.json): - 0.2.1 to 0.3.0. minAppVersion unchanged at 1.8.10. Engineering changelog entries (changelog/): - 2026-05-26_02.md — the structural idle-timeout port. - 2026-05-27_01.md — the two new templates, max-tokens override, and rendering-discipline partial work. Includes the diagnostic-led narrative on the vault-drift bug that caused the 4-of-5 broken-Mermaid rate. Release narratives: - changelog/releases/0.3.0.md — full marketing-quality release narrative with frontmatter, four-audience cascade, three diagnostic-led stories (streaming-timeout, max_tokens, rendering-discipline), explicit upgrade notes including the vault-drift warning, three deferred items for 0.4.x. - release-notes/0.3.0.md — prose-only release-page body picked up by the release.yml workflow when the 0.3.0 tag is pushed. Tighter cut of the same narrative, suited for the GitHub release page. Context-v stamp: - context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md marked status: resolved, date_resolved 2026-05-26, with the four open items reorganized into "what landed" (3 of 4) and "deferred follow-ups" (cross-service audit, settings-pane exposure, deep-research detection robustness). Files changed: - manifest.json, package.json, versions.json - README.md, docs/directory-templates.md - src/services/directoryTemplateService.ts - src/services/templateSeederService.ts - src/docs/templates/README.md - src/docs/templates/concept-profile.md - src/docs/templates/market-map-profile.md - src/docs/templates/market-category-profile.md (new) - src/docs/templates/standards-and-specs-profile.md (new) - src/docs/partials/mermaid-discipline.md - src/docs/partials/latex-discipline.md (new) - changelog/2026-05-26_02.md (new) - changelog/2026-05-27_01.md (new) - changelog/releases/0.3.0.md (new) - release-notes/0.3.0.md (new) - context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 96df705 commit f946973

19 files changed

Lines changed: 1572 additions & 76 deletions

README.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33

44
**Perplexed** is an Obsidian plugin that enables AI-powered content generation with source citations using [Perplexity](https://www.perplexity.ai/), [Anthropic Claude](https://www.anthropic.com/), [Google Gemini](https://ai.google.dev/) (with Google Search grounding), and [Perplexica / Vane](https://github.com/ItzCrazyKns/Vane) (self-hosted). This plugin brings research-grade AI capabilities directly into your Obsidian workspace, allowing you to generate well-cited content for your notes.
55

6+
## 💼 For Venture Capital, Private Equity, and Equities-Trading Workflows
7+
8+
Perplexed ships a set of **analyst-grade directory templates** aimed at the research deliverables a VC analyst, PE associate, equity-research analyst, or trading-desk strategist produces daily. Drop an empty file into the matching folder, run *Apply directory template to current file*, and Perplexity Deep Research returns a 6-9K-word cited analyst draft you can curate into a memo for a partner, an IC, or a portfolio review.
9+
10+
| Workflow | Template | What it produces |
11+
|---|---|---|
12+
| **Naming the players in a category** (incumbents vs challengers vs innovators by financial stage) | `market-category-profile.md``concepts/Market-Categories/` | Three-tier company landscape with explicit definitions: **Incumbents** (public / late-stage private / PE-owned), **Challengers** (Series C+ scale-ups, recently public), **Innovators** (Pre-Seed through Series B). Plus Why Now / What's Happening sections covering CAGR + category-creation momentum, and an Industry Coverage section sub-grouped into Market Reports (Gartner, IDC, Forrester, ABI) / Industry Articles / Financial News (Bloomberg, FT, Pitchbook). |
13+
| **Authoring a market map** (Known Category or Thesis-Driven) | `market-map-profile.md``lost-in-public/market-maps/` | Analyst-grade memo with 4-8 sub-segments, 20-40 named innovator cards (Offering / Funding / Why-they-matter / Coverage), Market Dynamics (Sizing / Adoption / Capital Flow), Frontier and Open Questions. Anti-incumbent editorial stance prevents big-tech over-representation. |
14+
| **Profiling an open spec or standard** an investment thesis depends on | `standards-and-specs-profile.md``Sources/Standards-and-Specs/` | Five-way authority typing (de-jure / consortium / vendor-led-open / community / de-facto), three-tier adoption framing with notable holdouts, named editors, stewardship-transition stories, named public critics with their arguments. |
15+
| **Catalogue an authoritative source** (book, person, channel, report, conference) | `source-profile.md``Sources/` | Type-aware emphasis (author / publisher / cadence / methodology), Google Books URL harvesting for books, signature-work catalog. |
16+
| **Encyclopedia entry on a concept, pattern, or mental model** the desk repeatedly invokes | `concept-profile.md``concepts/` | Definition, usage, history, examples, case studies. Mermaid + LaTeX rendering discipline baked in for diagrams and formulas. |
17+
18+
Every analyst-grade template runs on `sonar-deep-research`, ships with idle-only timeout safety (`request-timeout-ms: 0`, per-chunk idle timer at 270s) and a 24,000-token output budget (`max-tokens: 24000`) — enough for the longest analyst drafts to land without silent mid-document truncation. See [Directory Templates](#directory-templates) below for the full set and the cft-block grammar for tuning your own.
19+
620
## 🎯 Key Features
721
![Perplexed UI Modal interface](https://i.imgur.com/jaZ4UfS.png)
822
- **Source-Cited AI Responses**: Get AI-generated content with proper citations and references
@@ -50,6 +64,7 @@ plugin directory.
5064
5165
## 📋 Table of Contents
5266
67+
- [For Venture Capital, Private Equity, and Equities-Trading Workflows](#-for-venture-capital-private-equity-and-equities-trading-workflows)
5368
- [User Onboarding](#user-onboarding)
5469
- [Installation](#installation)
5570
- [Initial Setup](#initial-setup)
@@ -435,9 +450,10 @@ Two peer folders alongside `templates/` keep editorial rules vault-visible and D
435450

436451
```
437452
Content-Dev/
438-
├── templates/ (your four profile templates)
439-
├── partials/ (reusable snippets: mermaid-discipline, etc.)
440-
│ └── mermaid-discipline.md
453+
├── templates/ (your seven profile templates)
454+
├── partials/ (reusable snippets included via {{include: name}})
455+
│ ├── mermaid-discipline.md (paired BAD/GOOD examples + 6-item self-check)
456+
│ └── latex-discipline.md (Obsidian MathJax delimiters + $ escaping)
441457
└── preambles/ (auto-attached to every request as system / user messages)
442458
├── inline-citation.md
443459
├── image-placement.md
@@ -452,16 +468,19 @@ Fix the mermaid quoting rule once in `partials/mermaid-discipline.md` and every
452468

453469
### Shipped templates
454470

455-
Four templates ship inlined into the plugin and seed into your vault on first plugin load:
471+
Seven templates ship inlined into the plugin and seed into your vault on first plugin load:
456472

457473
| File | Targets | Use for |
458474
|---|---|---|
459-
| `concept-profile.md` | `concepts/**` | Encyclopedia-style entries on ideas, patterns, mental models. Anti-incumbent editorial stance baked in (tech giants treated as adopters/popularizers, not innovators, unless documented heyday-era origination supports otherwise). |
475+
| `concept-profile.md` | `concepts/**` | Encyclopedia-style entries on ideas, patterns, mental models. Anti-incumbent editorial stance baked in (tech giants treated as adopters/popularizers, not innovators, unless documented heyday-era origination supports otherwise). Includes both `mermaid-discipline` and `latex-discipline` partials. |
460476
| `vocabulary-profile.md` | `Vocabulary/**` | Term definitions with disambiguation through an innovation-consulting lens. |
461477
| `source-profile.md` | `Sources/**` | Profiles of books, people, channels, publications, journals, reports, events — type-aware, with Google Books URL harvesting for books. |
462478
| `toolkit-profile.md` | `Tooling/**` | Profiles of tools, products, platforms, frameworks. |
479+
| `market-map-profile.md` | `lost-in-public/market-maps/**`, `market-maps/**` | Analyst-grade market-map drafts — both Known Category (e.g., Humanoid Robots) and Thesis-Driven (e.g., Neural Network Hardware as Brains for Robotics). Runs on `sonar-deep-research` with idle-only timeout, `max-tokens: 24000`, and a 40-min absolute wall-clock ceiling. |
480+
| `standards-and-specs-profile.md` | `Sources/Standards-and-Specs/**`, `Standards-and-Specs/**` | Analyst-grade profiles of open specs and standards. Five-way authority typing (de-jure / consortium / vendor-led-open / community / de-facto). Three-tier structural adoption framing (incumbents / challengers / innovators) plus notable holdouts. Named editors, stewardship transitions, named critics. |
481+
| `market-category-profile.md` | `concepts/Market-Categories/**`, `Market-Categories/**` | Concept-folder reference card for a named market category. Three-tier company landscape with explicit FINANCIAL-STAGE definitions: Incumbents (public / late-stage private / PE-owned) → Challengers (Series C+ scale-ups, recently public) → Innovators (Pre-Seed through Series B). Separate Why Now / What's Happening sections covering CAGR + category-creation momentum. Industry Coverage sub-grouped into Market Reports / Industry Articles / Financial News. |
463482

464-
All four use Perplexity's `sonar-pro` (deep-research is unreliable for image return).
483+
The first four templates use Perplexity's `sonar-pro`. The three deep-research templates (`market-map-profile`, `standards-and-specs-profile`, `market-category-profile`) use `sonar-deep-research` and declare per-template cft-block overrides for the wall-clock ceiling (`request-timeout-ms`), the per-chunk idle timer (`stream-idle-timeout-ms`), and the Perplexity output-token budget (`max-tokens: 24000`). See [`docs/directory-templates.md`](docs/directory-templates.md) for the full cft-block grammar and the diagnostic table for distinguishing wall-clock-timeout truncation from max_tokens truncation.
465484

466485
### Auto-seed behavior
467486

changelog/2026-05-26_02.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
---
2+
title: "Long deep-research streams no longer get cut off at the ceiling — the timer now resets every time bytes arrive"
3+
lede: "The per-chunk idle-timeout discipline the legacy modal flow has used for two iterations now governs the directory-template flow too. A healthy slow stream completes naturally; a silently-stalled one fails in seconds instead of minutes."
4+
date_work_started: 2026-05-26
5+
date_work_completed: 2026-05-26
6+
date_created: 2026-05-26
7+
date_modified: 2026-05-26
8+
publish: true
9+
category: Changelog
10+
tags:
11+
- Directory-Templates
12+
- Streaming-Timeouts
13+
- Deep-Research
14+
- Idle-Timeout
15+
- cft-Block
16+
- Perplexity-sonar-deep-research
17+
- Structural-Fix
18+
authors:
19+
- Michael Staton
20+
augmented_with:
21+
- Claude Code on Claude Opus 4.7 (1M context)
22+
files_changed:
23+
- src/services/directoryTemplateService.ts
24+
- docs/directory-templates.md
25+
- src/docs/templates/README.md
26+
- src/docs/templates/market-map-profile.md
27+
- context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md
28+
---
29+
30+
# The structural fix the morning's market-map run earned
31+
32+
## Why care?
33+
34+
If you run any directory template on Perplexity — especially the long deep-research templates like `market-map-profile` — your timeouts now behave the way you'd intuit they should. **A stream that is healthily producing bytes runs as long as it needs to run.** A stream that goes silent (Perplexity rate-limit, socket close, upstream stall) surfaces the failure inside seconds, not at the end of a 30-minute ceiling. The change is invisible when everything goes well and only noticeable when something would have gone wrong — which is when you most want it noticeable.
35+
36+
Earlier today we shipped a market-map template, watched it produce a beautiful 7,500-word draft on Humanoid Robots, and then watched the last sentence cut off mid-word because the wall-clock timer fired before the stream finished. We patched the immediate pain by raising the ceiling. **This entry is the structural fix underneath it.**
37+
38+
## What's new?
39+
40+
A single concept: the timer that decides "is this stream still alive?" is now armed *per chunk*, not once per request.
41+
42+
- **Old behavior.** One `setTimeout(controller.abort, timeoutMs)` at fetch time. If the stream takes longer than `timeoutMs`, even by one byte, abort. If the stream goes silent for 27 of the 30 allotted minutes, wait the full 30 anyway before noticing.
43+
- **New behavior.** Each `reader.read()` is raced against a fresh timer. As long as bytes keep arriving, the timer is cleared and re-armed. The stream is only killed if it goes **quiet** for `idleMs` — by default 270 seconds for deep-research models, 90 seconds for everything else.
44+
45+
Two cft-block keys now govern timeouts (both optional):
46+
47+
```cft
48+
provider: perplexity
49+
model: sonar-deep-research
50+
stream-idle-timeout-ms: 270000 # per-chunk idle (default already 270s for deep-research)
51+
request-timeout-ms: 2400000 # absolute wall-clock ceiling (40 min)
52+
system: |
53+
...
54+
```
55+
56+
`stream-idle-timeout-ms:` is the new primary safety. `request-timeout-ms:` is the legacy key, now repurposed as an opt-in absolute ceiling — set to `0` to disable and rely on idle-only.
57+
58+
## How it works
59+
60+
Two different streaming primitives have lived in this codebase since the directory-template flow forked from the legacy `PerplexityModal` flow. The legacy modal moved to per-chunk idle-timeout discipline two iterations ago after the same problem hit users there first. The directory-template flow never received the backport — until today.
61+
62+
The pattern, ported from `perplexityService.ts:659-668` into `streamPerplexityToFile`:
63+
64+
```ts
65+
const readWithIdleTimeout = (): Promise<ReadableStreamReadResult<Uint8Array>> => {
66+
let timer: number | undefined;
67+
const timeout = new Promise<never>((_, reject) => {
68+
timer = activeWindow.setTimeout(() => {
69+
reject(new Error(`stream went idle for ${idleMs / 1000}s (likely API stall, rate limit, or socket close)`));
70+
}, idleMs);
71+
});
72+
return Promise.race([reader.read(), timeout]).finally(() => {
73+
if (timer !== undefined) activeWindow.clearTimeout(timer);
74+
});
75+
};
76+
77+
// inside the read loop:
78+
({ value, done } = await readWithIdleTimeout());
79+
```
80+
81+
`Promise.race([reader.read(), timeout])` resolves with whichever wins. If a byte arrives, the `.finally()` clears the timer before it can fire and the loop continues. If the timer fires first, it rejects, the surrounding catch sets `truncated = true`, the existing cleanup pipeline flushes whatever already arrived, and the run returns with a partial-but-cited draft on disk and a Notice telling the user to re-run.
82+
83+
The `AbortController` stays — both as the cancel mechanism for the user-initiated *Cancel* command, and as the abort target for the optional wall-clock ceiling. The two timers are complementary: idle handles "is this stream alive right now?" and ceiling handles "regardless, do not let this run forever."
84+
85+
### The two pathologies the old design handled poorly
86+
87+
**Shape 1 — slow but healthy stream.** Deep-research generations on long templates sustain a slow trickle of tokens for tens of minutes. The old wall-clock cap killed them at the ceiling regardless of whether they were still producing. The idle timer lets them complete as long as bytes keep arriving inside the idle window. (The ceiling is still there if you want a hard cap — it's just not what's making the moment-to-moment safety decision anymore.)
88+
89+
**Shape 2 — silently stalled stream.** Conversely, a stream may go quiet at minute 3 (Perplexity rate-limit, socket close, upstream stall) and the old wall-clock cap wouldn't notice until minute 30. The user stared at an empty file for 27 unnecessary minutes. The idle timer surfaces the failure within `idleMs` seconds — fast feedback when something is genuinely wrong.
90+
91+
Both shapes are real. The wall-clock pattern punished healthy-but-slow while tolerating stalled-but-silent. The idle-timeout pattern inverts both — slow-but-healthy completes; stalled-but-silent fails fast.
92+
93+
## Migration notes
94+
95+
**Nothing breaks for existing templates.** The `request-timeout-ms:` key is still honored where declared; it just means "absolute wall-clock ceiling" now instead of "the only timer at all." Templates that didn't declare it still inherit `settings.requestTimeoutMs` as their ceiling. `market-map-profile.md` keeps its `2400000` (40 min) value — under the new semantics it's the ceiling on top of the 270s idle timer, which is exactly what an analyst-grade deep-research budget should look like.
96+
97+
To get **truly unbounded healthy streams** (idle-only safety, no ceiling), set `request-timeout-ms: 0` in the cft block, or set the plugin-level *Request timeout (ms)* setting to `0`. The idle timer will catch silent stalls fast either way.
98+
99+
To override **the idle timer itself**, declare `stream-idle-timeout-ms: <number>` in the cft block. The defaults (270s deep, 90s normal) match the legacy modal flow and have been load-bearing there for two iterations, so most templates won't need to touch this.
100+
101+
## What's deferred
102+
103+
The [open issue](../context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md) listed four follow-ups. This entry closes items 1 and 2 (the port itself, and the dual-key naming decision). Two remain explicitly deferred:
104+
105+
- **Cross-service audit.** The same wall-clock pathology may live in the Gemini service, the LM Studio service, and the Claude streaming flows. The idle-timeout discipline should be the house style across all of them; the audit is its own change.
106+
- **Settings-pane exposure of idle defaults.** Today the 270s/90s values are hardcoded in `streamPerplexityToFile` (matching `perplexityService.ts`). Exposing them as plugin settings is a follow-up if we ever need to tune them without a code change.
107+
108+
The deep-research detection is by model-name regex (`/deep-research/i`) — the same shape `perplexityService.ts` uses. Robust enough for today's Perplexity model lineup; revisit if Perplexity ever ships a long-running model under a different naming convention.
109+
110+
## Why this matters for the multi-stage exploration
111+
112+
The [Multi-Stage Cooperative Claude + Perplexity with RAG exploration](../context-v/explorations/Multi-Stage-Cooperative-Claude-and-Perplexity-with-RAG.md) explicitly listed this fix as upstream of the multi-stage spec. Reason: the eventual Claude editorial pass on a 7-8K-word draft is itself a long generation that would hit the same wall-clock cliff. With per-chunk idle-timeout discipline now load-bearing in the directory-template flow, the editorial pass can reuse the same `readWithIdleTimeout` primitive when it lands. The multi-stage spec is now unblocked on this dimension.
113+
114+
## Files touched
115+
116+
- `src/services/directoryTemplateService.ts``streamPerplexityToFile` signature changed from `timeoutMs: number` to `timeouts: { idleMs: number; ceilingMs: number }`. `readWithIdleTimeout()` helper added. Callsite in `applyTemplate` resolves both keys from cft config with sensible fallbacks (idle defaults from deep-research detection, ceiling defaults from `settings.requestTimeoutMs`, explicit `0` disables ceiling).
117+
- `docs/directory-templates.md`*Per-template timeout override* section rewritten as *Per-template timeout overrides* (plural), now documents both keys, the two pathologies the idle timer fixes, and the migration semantics.
118+
- `src/docs/templates/README.md` — cft-key list updated to mention both keys.
119+
- `src/docs/templates/market-map-profile.md` — inline comment on the `request-timeout-ms` declaration rewritten to explain it as the absolute ceiling on top of the 270s idle timer.
120+
- `context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md` — referenced as the canonical issue this closes.

0 commit comments

Comments
 (0)