@lincoln504/pi-research 1.4.3 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.mjs +192 -45
  3. package/dist/prompts/research-knowledge-relevance-triage.md +2 -0
  4. package/dist/prompts/research-knowledge-search-extractor.md +2 -0
  5. package/dist/prompts/researcher.md +2 -14
  6. package/dist/thread-worker.mjs +1 -1
  7. package/docs/AGENT-SKILL.md +4 -3
  8. package/docs/CHANGELOG.md +45 -1
  9. package/docs/CONFIGURATION.md +1 -1
  10. package/docs/SDK.md +1 -1
  11. package/package.json +1 -1
  12. package/skills/pi-research/SKILL.md +1 -1
  13. package/src/cli.ts +44 -3
  14. package/src/config.ts +26 -9
  15. package/src/constants.ts +23 -4
  16. package/src/core/llm/research-model-resolver.ts +38 -0
  17. package/src/core/planning-service.ts +12 -1
  18. package/src/index.ts +3 -1
  19. package/src/infrastructure/browser/thread-worker-messaging.ts +5 -1
  20. package/src/infrastructure/browser/thread-worker.mjs +1 -1
  21. package/src/infrastructure/embedding/embedding-server.ts +29 -9
  22. package/src/knowledge/store.ts +60 -4
  23. package/src/observers/research-observer-impl.ts +14 -6
  24. package/src/orchestration/quick-research-orchestrator.ts +29 -10
  25. package/src/orchestration/research-synthesis-service.ts +32 -0
  26. package/src/orchestration/researcher-executor.ts +31 -16
  27. package/src/orchestration/researcher.ts +2 -2
  28. package/src/orchestration/session-state.ts +19 -4
  29. package/src/prompts/research-knowledge-relevance-triage.md +2 -0
  30. package/src/prompts/research-knowledge-search-extractor.md +2 -0
  31. package/src/prompts/researcher.md +2 -14
  32. package/src/sdk.ts +6 -0
  33. package/src/tools/index.ts +2 -1
  34. package/src/tools/research-knowledge-search.ts +37 -4
  35. package/src/tools/research-tool-definition.ts +27 -16
  36. package/src/tools/scrape.ts +8 -1
  37. package/src/utils/log-utils.ts +5 -2
  38. package/src/utils/metrics-summary.ts +21 -1
  39. package/src/utils/tool-usage-tracker.ts +6 -3
  40. package/src/web-research/web-scraper.ts +9 -0
  41. package/src/youtube/index.ts +11 -1
@@ -75,6 +75,15 @@ async function convertToMarkdown(html: string): Promise<string> {
75
75
  return converter(html);
76
76
  }
77
77
 
78
+ // TODO(hardening, medium): this synchronous WASM parse runs on the MAIN
79
+ // process's event loop — a large/complex PDF can block it for seconds,
80
+ // starving every concurrent scrape, the TUI render loop, and timers. The
81
+ // correct fix is a worker_threads-based extraction (mirroring the browser
82
+ // pool's CPU isolation pattern), but it is deliberately NOT done in this
83
+ // pass: pdf-oxide-wasm is dynamically imported here and unit tests mock the
84
+ // module via vitest, which cannot reach into a real worker thread — moving
85
+ // the parse requires a companion test-seam redesign first. Bounded today by
86
+ // MAX_PDF_SIZE (100MB) and the scrape task's own deadline.
78
87
  async function extractPdfToMarkdown(bytes: Uint8Array): Promise<string> {
79
88
  if (bytes.length > MAX_PDF_SIZE) {
80
89
  const sizeMB = Math.round(bytes.length / 1024 / 1024);
@@ -10,6 +10,8 @@ import type { AgentToolResult } from '@earendil-works/pi-coding-agent';
10
10
  import { selectVideoIds } from './video-id.ts';
11
11
  import { fetchVideoTranscripts, type VideoTranscript } from './transcript-client.ts';
12
12
  import { metrics } from '../utils/metrics.ts';
13
+ import { truncateWithMarker } from '../utils/text-utils.ts';
14
+ import { MAX_SCRAPE_CONTENT_CHARS_PER_DOC } from '../constants.ts';
13
15
 
14
16
  export interface YoutubeTranscriptCommandOptions {
15
17
  urls: string[];
@@ -131,7 +133,15 @@ function formatResults(results: VideoTranscript[], rejected: string[]): string {
131
133
  // model can copy verbatim; omitting the line entirely for untitled videos
132
134
  // left them without any prompt-visible citation string to reuse.
133
135
  md += `**Cite as:** ${r.url}${r.title ? ` — '${r.title}'${r.author ? ` by ${r.author}` : ''}` : ''}\n`;
134
- md += `\n${r.text}\n\n---\n\n`;
136
+ // Per-document cap on content entering LLM context — parity with the
137
+ // scrape tool's own MAX_SCRAPE_CONTENT_CHARS_PER_DOC guard. The raw HTTP
138
+ // body is capped at 32MB (readTextCapped) and the knowledge-store
139
+ // ingestion path truncates too, but this tool's direct response to the
140
+ // calling agent had no cap of its own: a single long/dense-captioned
141
+ // video (a multi-hour livestream VOD, worst case with maxVideos up to 5)
142
+ // could inject an unbounded, multi-megabyte payload straight into the
143
+ // researcher's context.
144
+ md += `\n${truncateWithMarker(r.text ?? '', MAX_SCRAPE_CONTENT_CHARS_PER_DOC)}\n\n---\n\n`;
135
145
  }
136
146
 
137
147
  if (failed.length > 0) {