@lincoln504/pi-research 1.6.8 → 1.6.10
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.
- package/README.md +4 -0
- package/agent-skill/pi-research/SKILL.md +1 -1
- package/dist/cli.mjs +113 -27
- package/dist/prompts/researcher.md +2 -2
- package/dist/thread-worker.mjs +3 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/CHANGELOG.md +29 -0
- package/docs/CONFIGURATION.md +2 -1
- package/docs/KNOWLEDGE-STORE.md +16 -8
- package/package.json +1 -1
- package/src/cli.ts +2 -0
- package/src/config.ts +38 -2
- package/src/constants.ts +24 -2
- package/src/healthcheck/index.ts +32 -13
- package/src/infrastructure/browser/thread-worker.mjs +3 -1
- package/src/infrastructure/knowledge-store-service.ts +13 -2
- package/src/knowledge/availability.ts +118 -0
- package/src/knowledge/index.ts +17 -1
- package/src/orchestration/quick-research-orchestrator.ts +5 -1
- package/src/orchestration/researcher-executor.ts +6 -0
- package/src/prompts/researcher.md +2 -2
- package/src/research-config.ts +45 -8
- package/src/tools/research-knowledge-search.ts +13 -4
- package/src/tools/scrape.ts +11 -7
- package/src/tui/tui-controller.ts +17 -0
package/src/tools/scrape.ts
CHANGED
|
@@ -17,9 +17,9 @@ import type { ToolUsageTracker } from '../utils/tool-usage-tracker.ts';
|
|
|
17
17
|
import type { SystemResearchState } from '../orchestration/deep-research-types.ts';
|
|
18
18
|
import { deduplicateUrls, normalizeUrl, getCachedScrapedContent, registerResearcherScrapes, buildSessionPoolFooter } from '../utils/shared-links.ts';
|
|
19
19
|
import {
|
|
20
|
-
MAX_SCRAPE_URLS,
|
|
21
20
|
BATCH_2_DEFAULT_CONCURRENCY,
|
|
22
21
|
getMaxScrapeBatches,
|
|
22
|
+
getMaxScrapeUrls,
|
|
23
23
|
DEFAULT_MODEL_CONTEXT_WINDOW,
|
|
24
24
|
MAX_SCRAPE_CONTENT_CHARS_PER_DOC,
|
|
25
25
|
} from '../constants.ts';
|
|
@@ -57,6 +57,10 @@ export function createScrapeTool(options: {
|
|
|
57
57
|
// enforced — a real, if harmless, missed-opportunity: the model would stop one
|
|
58
58
|
// batch short of what it was actually allowed to use.
|
|
59
59
|
const maxScrapeBatches = options.tracker?.getToolLimit('scrape') ?? getMaxScrapeBatches(config);
|
|
60
|
+
// One resolved value feeds the tool schema text, the batch-protocol text, the
|
|
61
|
+
// per-call slice, and the over-cap report — the enforced cap and every string
|
|
62
|
+
// the model sees are the same number by construction.
|
|
63
|
+
const maxScrapeUrls = getMaxScrapeUrls(config);
|
|
60
64
|
const container = tryGetServiceContainerFromCtx(options.ctx);
|
|
61
65
|
|
|
62
66
|
// Fallback global state when no orchestration context is provided
|
|
@@ -78,7 +82,7 @@ export function createScrapeTool(options: {
|
|
|
78
82
|
});
|
|
79
83
|
|
|
80
84
|
const ScrapeParamsSchema = Type.Object({
|
|
81
|
-
urls: Type.Array(Type.String({ description: `The URLs to scrape (only the first ${
|
|
85
|
+
urls: Type.Array(Type.String({ description: `The URLs to scrape (only the first ${maxScrapeUrls} are fetched per call; extras are reported under "Not Fetched" rather than silently dropped)` }), { minItems: 1, maxItems: 20 }),
|
|
82
86
|
maxConcurrency: Type.Optional(Type.Number({ default: config.MAX_CONCURRENT_SCRAPES, minimum: 1, maximum: 20 })),
|
|
83
87
|
});
|
|
84
88
|
|
|
@@ -92,7 +96,7 @@ export function createScrapeTool(options: {
|
|
|
92
96
|
batchProtocolText = `PROTOCOL: Batch 1 → Batch 2 → ... (up to ${effectiveLimit} batches)`;
|
|
93
97
|
} else {
|
|
94
98
|
const batchNumbers = Array.from({ length: effectiveLimit }, (_, i) => `Batch ${i + 1}`).join(' → ');
|
|
95
|
-
batchProtocolText = `PROTOCOL: ${batchNumbers} (up to ${
|
|
99
|
+
batchProtocolText = `PROTOCOL: ${batchNumbers} (up to ${maxScrapeUrls} URLs each).`;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
return {
|
|
@@ -102,7 +106,7 @@ export function createScrapeTool(options: {
|
|
|
102
106
|
promptSnippet: `Read full content of web pages or PDFs (up to ${maxScrapeBatches} batches)`,
|
|
103
107
|
promptGuidelines: [
|
|
104
108
|
batchProtocolText,
|
|
105
|
-
`Up to ${
|
|
109
|
+
`Up to ${maxScrapeUrls} URLs per batch.`,
|
|
106
110
|
'Handshake is ELIMINATED. Start scraping immediately.',
|
|
107
111
|
'PDFs are auto-detected and extracted with high fidelity.',
|
|
108
112
|
],
|
|
@@ -175,8 +179,8 @@ export function createScrapeTool(options: {
|
|
|
175
179
|
// in results nor in Failed-to-Scrape, and the session-pool footer excludes the
|
|
176
180
|
// current batch).
|
|
177
181
|
const fetchCandidates = [...dedupedUrls, ...evictedDuplicates];
|
|
178
|
-
const finalUrls = fetchCandidates.slice(0,
|
|
179
|
-
const skippedUrls = fetchCandidates.slice(
|
|
182
|
+
const finalUrls = fetchCandidates.slice(0, maxScrapeUrls);
|
|
183
|
+
const skippedUrls = fetchCandidates.slice(maxScrapeUrls);
|
|
180
184
|
|
|
181
185
|
// Context gate: block if projected token usage would exceed threshold
|
|
182
186
|
if (options.getTokensUsed) {
|
|
@@ -364,7 +368,7 @@ export function createScrapeTool(options: {
|
|
|
364
368
|
|
|
365
369
|
if (skippedUrls.length > 0) {
|
|
366
370
|
markdown += `## Not Fetched — Over Batch Cap (${skippedUrls.length})\n\n`;
|
|
367
|
-
markdown += `Only the first ${
|
|
371
|
+
markdown += `Only the first ${maxScrapeUrls} URLs of a batch are fetched. The following URLs were NOT fetched — no content for them appears above. Request them in a later scrape batch if still needed:\n`;
|
|
368
372
|
for (const url of skippedUrls) {
|
|
369
373
|
markdown += `- ${url}\n`;
|
|
370
374
|
}
|
|
@@ -66,6 +66,23 @@ export function initGlobalTuiController(ui: ExtensionUIContext, piSessionId?: st
|
|
|
66
66
|
// Check for specific global cancel keys (Escape and Ctrl+C)
|
|
67
67
|
// We only trigger abort if research is actually running.
|
|
68
68
|
if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {
|
|
69
|
+
// Ctrl+C is pi's app.clear ("Clear editor"), NOT its cancel key — pi's own
|
|
70
|
+
// handleCtrlC() clears the editor text and never interrupts the agent (Esc
|
|
71
|
+
// is app.interrupt). Aborting the run on every Ctrl+C stole the key from
|
|
72
|
+
// users who merely wanted to discard typed text mid-run. Follow pi's
|
|
73
|
+
// convention: with text in the editor, Ctrl+C only clears (fall through and
|
|
74
|
+
// let pi do the clearing); an EMPTY editor is an explicit cancel gesture and
|
|
75
|
+
// aborts the active research.
|
|
76
|
+
if (matchesKey(data, 'ctrl+c')) {
|
|
77
|
+
let editorText = '';
|
|
78
|
+
try {
|
|
79
|
+
editorText = typeof ui.getEditorText === 'function' ? (ui.getEditorText() ?? '') : '';
|
|
80
|
+
} catch { /* editor gone mid-run — treat as empty (cancel) */ }
|
|
81
|
+
if (editorText.length > 0) {
|
|
82
|
+
logger.debug('[TUI] Ctrl+C with editor text — clearing only, research keeps running.');
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
69
86
|
const activeCount = getActiveSessionCount();
|
|
70
87
|
if (activeCount > 0) {
|
|
71
88
|
// FIX (New Issues B & E): Use abortAllSessions scoped to the current Pi session
|