@lincoln504/pi-research 0.0.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/config/searxng/default-settings.yml +189 -0
  4. package/config/searxng/limiter.toml +34 -0
  5. package/config/tooling/eslint.config.js +73 -0
  6. package/config/tooling/vitest.config.integration.ts +17 -0
  7. package/config/tooling/vitest.config.ts +40 -0
  8. package/config/tooling/vitest.config.unit.ts +12 -0
  9. package/docs/ARCHITECTURE.md +109 -0
  10. package/docs/assets/README-banner.jpg +0 -0
  11. package/package.json +92 -0
  12. package/scripts/setup.js +174 -0
  13. package/src/config.ts +206 -0
  14. package/src/constants.ts +148 -0
  15. package/src/healthcheck/index.ts +309 -0
  16. package/src/index.ts +71 -0
  17. package/src/infrastructure/searxng-lifecycle.ts +577 -0
  18. package/src/infrastructure/searxng-manager.ts +1173 -0
  19. package/src/infrastructure/state-manager.ts +918 -0
  20. package/src/logger.ts +246 -0
  21. package/src/orchestration/deep-research-orchestrator.ts +848 -0
  22. package/src/orchestration/deep-research-reducer.ts +129 -0
  23. package/src/orchestration/deep-research-types.ts +54 -0
  24. package/src/orchestration/id-utils.ts +63 -0
  25. package/src/orchestration/researcher.ts +104 -0
  26. package/src/orchestration/session-context.ts +43 -0
  27. package/src/prompts/research-tool-usage.md +45 -0
  28. package/src/prompts/researcher.md +166 -0
  29. package/src/prompts/system-coordinator.md +24 -0
  30. package/src/prompts/system-lead-evaluator.md +225 -0
  31. package/src/security/cisa-kev.ts +242 -0
  32. package/src/security/github-advisories.ts +607 -0
  33. package/src/security/index.ts +406 -0
  34. package/src/security/nvd.ts +532 -0
  35. package/src/security/osv.ts +487 -0
  36. package/src/security/types.ts +138 -0
  37. package/src/stackexchange/cache.ts +111 -0
  38. package/src/stackexchange/index.ts +352 -0
  39. package/src/stackexchange/output/compact.ts +64 -0
  40. package/src/stackexchange/output/index.ts +7 -0
  41. package/src/stackexchange/output/json.ts +21 -0
  42. package/src/stackexchange/output/table.ts +123 -0
  43. package/src/stackexchange/queries.ts +168 -0
  44. package/src/stackexchange/rest-client.ts +127 -0
  45. package/src/stackexchange/types.ts +129 -0
  46. package/src/tool.ts +430 -0
  47. package/src/tools/grep.ts +335 -0
  48. package/src/tools/index.ts +77 -0
  49. package/src/tools/scrape.ts +451 -0
  50. package/src/tools/search.ts +188 -0
  51. package/src/tools/security.ts +292 -0
  52. package/src/tools/stackexchange.ts +101 -0
  53. package/src/tui/research-panel.ts +576 -0
  54. package/src/tui/searxng-status.ts +80 -0
  55. package/src/types/extension-context.ts +60 -0
  56. package/src/types/llm.ts +111 -0
  57. package/src/utils/inject-date.ts +29 -0
  58. package/src/utils/input-validation.ts +103 -0
  59. package/src/utils/json-utils.ts +262 -0
  60. package/src/utils/make-resource-loader.ts +43 -0
  61. package/src/utils/research-error.ts +205 -0
  62. package/src/utils/research-export.ts +199 -0
  63. package/src/utils/searxng-config.ts +94 -0
  64. package/src/utils/session-state.ts +295 -0
  65. package/src/utils/shared-links.ts +123 -0
  66. package/src/utils/shutdown-manager.ts +54 -0
  67. package/src/utils/text-utils.ts +83 -0
  68. package/src/utils/tool-usage-tracker.ts +135 -0
  69. package/src/web-research/dependencies.ts +20 -0
  70. package/src/web-research/retry-utils.ts +232 -0
  71. package/src/web-research/scrapers.ts +935 -0
  72. package/src/web-research/search.ts +235 -0
  73. package/src/web-research/types.ts +47 -0
  74. package/src/web-research/utils.ts +158 -0
  75. package/tsconfig.json +40 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Deep Research Reducer
3
+ *
4
+ * PURE FUNCTION logic for state transitions.
5
+ * Contains 0 side effects. 100% testable without mocks.
6
+ */
7
+
8
+ import type { SystemResearchState, DeepResearchEvent } from './deep-research-types.ts';
9
+
10
+ export function deepResearchReducer(state: SystemResearchState, event: DeepResearchEvent): SystemResearchState {
11
+ // Deep clone state to ensure true purity
12
+ const newState: SystemResearchState = {
13
+ ...state,
14
+ lastUpdated: Date.now(),
15
+ initialAgenda: [...state.initialAgenda],
16
+ allScrapedLinks: [...state.allScrapedLinks],
17
+ aspects: { ...state.aspects }
18
+ };
19
+
20
+ switch (event.type) {
21
+ case 'PLANNING_COMPLETE': {
22
+ newState.initialAgenda = event.agenda;
23
+ newState.status = 'researching';
24
+ // Assign first batch to aspects
25
+ event.agenda.slice(0, event.initialCount).forEach((q: string, i: number) => {
26
+ const id = `1.${i + 1}`;
27
+ newState.aspects[id] = { id, query: q, status: 'pending' };
28
+ });
29
+ break;
30
+ }
31
+
32
+ case 'SIBLING_STARTED': {
33
+ const aspect = newState.aspects[event.id];
34
+ if (aspect) {
35
+ newState.aspects[event.id] = {
36
+ ...aspect,
37
+ status: 'running'
38
+ };
39
+ }
40
+ break;
41
+ }
42
+
43
+ case 'SIBLING_COMPLETED': {
44
+ const aspect = newState.aspects[event.id];
45
+ if (aspect) {
46
+ newState.aspects[event.id] = {
47
+ ...aspect,
48
+ status: 'completed',
49
+ report: event.report
50
+ };
51
+ }
52
+ break;
53
+ }
54
+
55
+ case 'SIBLING_FAILED': {
56
+ const aspect = newState.aspects[event.id];
57
+ if (aspect) {
58
+ newState.aspects[event.id] = {
59
+ ...aspect,
60
+ status: 'failed',
61
+ error: event.error
62
+ };
63
+ }
64
+ break;
65
+ }
66
+
67
+ case 'SIBLING_TOKENS': {
68
+ const aspect = newState.aspects[event.id];
69
+ if (aspect) {
70
+ // Accumulate tokens and cost for this sibling
71
+ const currentTokens = aspect.tokens || 0;
72
+ const currentCost = aspect.cost || 0;
73
+ newState.aspects[event.id] = {
74
+ ...aspect,
75
+ tokens: currentTokens + event.tokens,
76
+ cost: currentCost + event.cost
77
+ };
78
+ }
79
+ break;
80
+ }
81
+
82
+ case 'LINKS_SCRAPED': {
83
+ newState.allScrapedLinks = [...new Set([...newState.allScrapedLinks, ...event.links])];
84
+ break;
85
+ }
86
+
87
+ case 'PROMOTION_STARTED': {
88
+ newState.promotedId = event.id;
89
+ break;
90
+ }
91
+
92
+ case 'PROMOTION_DECISION': {
93
+ if (event.finalSynthesis !== undefined) {
94
+ // Case 1: Lead Evaluator chose to synthesize - complete with synthesis
95
+ newState.finalSynthesis = event.finalSynthesis;
96
+ newState.status = 'completed';
97
+ newState.promotedId = undefined;
98
+ } else if (event.nextQueries.length > 0 && newState.currentRound < event.maxRounds) {
99
+ // Case 2: Lead Evaluator chose to continue AND we're under max rounds
100
+ newState.currentRound++;
101
+ newState.status = 'researching';
102
+ newState.promotedId = undefined; // Reset for new round
103
+ event.nextQueries.forEach((q: string, i: number) => {
104
+ const id = `${newState.currentRound}.${i + 1}`;
105
+ newState.aspects[id] = { id, query: q, status: 'pending' };
106
+ });
107
+ } else {
108
+ // Case 3: Max rounds reached OR no next queries
109
+ // Note: Per lead-evaluator prompt, when max rounds are reached, the evaluator
110
+ // should synthesize. If nextQueries are provided at max rounds, this is a
111
+ // protocol violation, and we enforce the constraint by completing anyway.
112
+ newState.status = 'completed';
113
+ newState.promotedId = undefined;
114
+ }
115
+ break;
116
+ }
117
+ }
118
+
119
+ return newState;
120
+ }
121
+
122
+ /**
123
+ * Utility to check if a round is finished
124
+ */
125
+ export function isRoundComplete(state: SystemResearchState, round: number): boolean {
126
+ const roundAspects = Object.values(state.aspects).filter(a => a.id.startsWith(`${round}.`));
127
+ if (roundAspects.length === 0) return false;
128
+ return roundAspects.every(a => a.status === 'completed' || a.status === 'failed');
129
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Deep Research Types
3
+ *
4
+ * Defines the schema for the monolithic ResearchState persisted in the session tree.
5
+ */
6
+
7
+ export type ResearchStatus = 'planning' | 'researching' | 'evaluating' | 'synthesizing' | 'completed' | 'failed';
8
+ export type SiblingStatus = 'pending' | 'running' | 'completed' | 'failed';
9
+
10
+ export type DeepResearchEvent =
11
+ | { type: 'PLANNING_COMPLETE'; agenda: string[]; initialCount: number }
12
+ | { type: 'SIBLING_STARTED'; id: string }
13
+ | { type: 'SIBLING_COMPLETED'; id: string; report: string }
14
+ | { type: 'SIBLING_FAILED'; id: string; error: string }
15
+ | { type: 'LINKS_SCRAPED'; links: string[] }
16
+ | { type: 'PROMOTION_STARTED'; id: string }
17
+ | { type: 'PROMOTION_DECISION'; nextQueries: string[]; finalSynthesis?: string; maxRounds: number }
18
+ | { type: 'SIBLING_TOKENS'; id: string; tokens: number; cost: number };
19
+
20
+ export interface ResearchSibling {
21
+ id: string; // e.g. "1.1", "2.1"
22
+ query: string;
23
+ status: SiblingStatus;
24
+ report?: string;
25
+ error?: string;
26
+ tokens?: number;
27
+ cost?: number;
28
+ }
29
+
30
+ export interface SystemResearchState {
31
+ version: number;
32
+ rootQuery: string;
33
+ complexity: 1 | 2 | 3; // 1: Normal, 2: Deep, 3: Ultra
34
+ currentRound: number;
35
+ status: ResearchStatus;
36
+ lastUpdated: number;
37
+
38
+ // The full exhaustive list of aspects planned by the initial coordinator
39
+ initialAgenda: string[];
40
+
41
+ // Global pool updated IMMEDIATELY by the scrape tool
42
+ allScrapedLinks: string[];
43
+
44
+ // Sequence of research aspects actively being worked or completed
45
+ aspects: {
46
+ [id: string]: ResearchSibling;
47
+ };
48
+
49
+ // Track who was promoted to Lead Evaluator in this round to prevent race conditions
50
+ promotedId?: string;
51
+
52
+ // Final result if completed
53
+ finalSynthesis?: string;
54
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Researcher ID Utilities
3
+ *
4
+ * Abstracts hierarchical IDs (1.1, 1.2, 2.1) to sequential display numbers (1, 2, 3)
5
+ * for cleaner UI while maintaining internal structure.
6
+ */
7
+
8
+ import type { SystemResearchState } from './deep-research-types.ts';
9
+
10
+ /**
11
+ * Get sequential display number for a researcher ID
12
+ *
13
+ * Maps internal hierarchical IDs to sequential display numbers:
14
+ * - Round 1: 1.1 → 1, 1.2 → 2, 1.3 → 3
15
+ * - Round 2: 2.1 → 4, 2.2 → 5, 2.3 → 6
16
+ * - Continue sequentially across all rounds
17
+ */
18
+ export function getDisplayNumber(state: SystemResearchState, internalId: string): string {
19
+ const aspects = Object.values(state.aspects).sort((a, b) => {
20
+ const aParts = a.id.split('.');
21
+ const bParts = b.id.split('.');
22
+ const aRound = parseInt(aParts[0] ?? '0');
23
+ const aNum = parseInt(aParts[1] ?? '0');
24
+ const bRound = parseInt(bParts[0] ?? '0');
25
+ const bNum = parseInt(bParts[1] ?? '0');
26
+
27
+ if (aRound !== bRound) return aRound - bRound;
28
+ return aNum - bNum;
29
+ });
30
+
31
+ const index = aspects.findIndex(a => a.id === internalId);
32
+ return index >= 0 ? (index + 1).toString() : internalId;
33
+ }
34
+
35
+ /**
36
+ * Get a researcher's role context
37
+ *
38
+ * Returns role information for a researcher:
39
+ * - Number in this round (1, 2, 3)
40
+ * - Total siblings in this round
41
+ * - Current round
42
+ */
43
+ export function getResearcherRoleContext(
44
+ state: SystemResearchState,
45
+ internalId: string
46
+ ): {
47
+ displayNumber: string;
48
+ roundNumber: number;
49
+ totalInRound: number;
50
+ isLastInRound: boolean;
51
+ } {
52
+ const parts = internalId.split('.');
53
+ const round = parseInt(parts[0] ?? '0');
54
+ const sibling = parseInt(parts[1] ?? '0');
55
+ const roundAspects = Object.values(state.aspects).filter(a => a.id.startsWith(`${round}.`));
56
+
57
+ return {
58
+ displayNumber: getDisplayNumber(state, internalId),
59
+ roundNumber: round,
60
+ totalInRound: roundAspects.length,
61
+ isLastInRound: sibling === roundAspects.length,
62
+ };
63
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Researcher Session Factory
3
+ *
4
+ * Responsible for instantiating individual researcher agent sessions.
5
+ * Each researcher is an autonomous agent equipped with a suite of specialized tools:
6
+ * - Web search via SearXNG
7
+ * - Context-aware URL scraping via Playwright
8
+ * - Security vulnerability database queries (NVD, CISA, OSV)
9
+ * - Technical Q&A retrieval from Stack Exchange
10
+ * - Local code search via Ripgrep
11
+ */
12
+
13
+ import type { AgentSession, ModelRegistry, SettingsManager, ExtensionContext } from '@mariozechner/pi-coding-agent';
14
+ import { createAgentSession, createReadTool, SessionManager } from '@mariozechner/pi-coding-agent';
15
+ import type { Model } from '@mariozechner/pi-ai';
16
+ import { createResearchTools } from '../tools/index.ts';
17
+ import { makeResourceLoader } from '../utils/make-resource-loader.ts';
18
+ import { ToolUsageTracker, createDefaultToolLimits } from '../utils/tool-usage-tracker.ts';
19
+ import type { SystemResearchState } from './deep-research-types.ts';
20
+
21
+ export interface CreateResearcherSessionOptions {
22
+ cwd: string;
23
+ ctxModel: Model<any> | undefined;
24
+ modelRegistry: ModelRegistry;
25
+ settingsManager: SettingsManager;
26
+ systemPrompt: string;
27
+ searxngUrl: string;
28
+ extensionCtx: ExtensionContext;
29
+ // Optional: real closures for global state management
30
+ getGlobalState?: () => SystemResearchState;
31
+ updateGlobalLinks?: (links: string[]) => void;
32
+ /** Returns tokens consumed by this researcher session so far (for context-aware scrape gating). */
33
+ getTokensUsed?: () => number;
34
+ /** Model context window size in tokens. */
35
+ contextWindowSize?: number;
36
+ }
37
+
38
+ export async function createResearcherSession(options: CreateResearcherSessionOptions): Promise<AgentSession> {
39
+ const {
40
+ cwd,
41
+ ctxModel,
42
+ modelRegistry,
43
+ settingsManager,
44
+ systemPrompt,
45
+ searxngUrl,
46
+ extensionCtx,
47
+ getGlobalState,
48
+ updateGlobalLinks,
49
+ getTokensUsed,
50
+ contextWindowSize,
51
+ } = options;
52
+
53
+ // Validate required parameters
54
+ if (!ctxModel) {
55
+ throw new Error('No model selected. Please select a model before using the research tool.');
56
+ }
57
+
58
+ if (!systemPrompt || typeof systemPrompt !== 'string') {
59
+ throw new Error('Invalid system prompt: must be a non-empty string');
60
+ }
61
+
62
+ if (!searxngUrl || typeof searxngUrl !== 'string') {
63
+ throw new Error('Invalid SearXNG URL: must be a non-empty string');
64
+ }
65
+
66
+ // Create tool usage tracker for this researcher
67
+ const tracker = new ToolUsageTracker(createDefaultToolLimits());
68
+
69
+ // Use provided closures or fallback to safe dummies
70
+ const globalState = getGlobalState || (() => ({} as any));
71
+ const globalLinks = updateGlobalLinks || (() => {});
72
+
73
+ try {
74
+ const result = await createAgentSession({
75
+ cwd,
76
+ tools: [createReadTool(cwd)],
77
+ customTools: createResearchTools({
78
+ searxngUrl,
79
+ ctx: extensionCtx,
80
+ tracker,
81
+ getGlobalState: globalState,
82
+ updateGlobalLinks: globalLinks,
83
+ getTokensUsed,
84
+ contextWindowSize,
85
+ }),
86
+ sessionManager: SessionManager.inMemory(), // Each researcher gets its own isolated session
87
+ settingsManager,
88
+ model: ctxModel,
89
+ modelRegistry,
90
+ resourceLoader: makeResourceLoader(systemPrompt),
91
+ });
92
+
93
+ if (!result || !result.session) {
94
+ throw new Error('Session creation returned invalid result');
95
+ }
96
+
97
+ return result.session;
98
+ } catch (error) {
99
+ const errorMsg = error instanceof Error ? error.message : String(error);
100
+ throw new Error(`Failed to create researcher session: ${errorMsg}`, {
101
+ cause: error,
102
+ });
103
+ }
104
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Session Context Formatter
3
+ *
4
+ * Formats the full parent session context for the initial coordinator.
5
+ * Returns the uncompacted history of the current conversation branch.
6
+ */
7
+
8
+ import type { ExtensionContext } from '@mariozechner/pi-coding-agent';
9
+ import {
10
+ buildSessionContext,
11
+ convertToLlm,
12
+ serializeConversation
13
+ } from '@mariozechner/pi-coding-agent';
14
+
15
+ /**
16
+ * Formats parent context for the initial coordinator.
17
+ * Provides the full linear history of the current branch.
18
+ */
19
+ export async function formatParentContext(ctx: ExtensionContext): Promise<string> {
20
+ const branch = ctx.sessionManager.getBranch();
21
+ const sessionContext = buildSessionContext(branch);
22
+ const allMessages = sessionContext.messages;
23
+
24
+ if (allMessages.length === 0) {
25
+ return 'No previous context available.';
26
+ }
27
+
28
+ // Limit context to prevent overflow for the initial coordinator
29
+ const MAX_CONTEXT_MESSAGES = 15;
30
+ const recentMessages = allMessages.length > MAX_CONTEXT_MESSAGES
31
+ ? allMessages.slice(-MAX_CONTEXT_MESSAGES)
32
+ : allMessages;
33
+
34
+ const llmMessages = convertToLlm(recentMessages);
35
+ const serialized = serializeConversation(llmMessages);
36
+
37
+ return [
38
+ '## Parent Conversation History',
39
+ 'The following is the recent history of the conversation branch for your reference:',
40
+ '',
41
+ serialized
42
+ ].join('\n');
43
+ }
@@ -0,0 +1,45 @@
1
+ ### 🔍 RESEARCH TOOL USAGE
2
+
3
+ **For any web/internet research questions, use the `research` tool.**
4
+
5
+ The `research` tool (from pi-research extension) is your tool for web/internet research.
6
+
7
+ ---
8
+
9
+ #### What counts as web research?
10
+
11
+ - Questions requiring current information (news, trends, latest developments)
12
+ - Questions about products, services, companies
13
+ - Questions requiring statistics or data
14
+ - Questions about people, places, events, or topics external to this project
15
+ - "What is X?", "How does X work?", "Tell me about X" questions
16
+
17
+ #### What is NOT web research (use other tools for these)
18
+
19
+ - Reading files in the project → use `read` tool
20
+ - Running commands or tests → use `bash` tool
21
+ - Analyzing code in this repository
22
+ - Questions about the project itself
23
+
24
+ ---
25
+
26
+ #### DEPTH PARAMETER — Controls research intensity
27
+
28
+ **DEFAULT:** Omit depth parameter (uses `depth: 0` - Quick mode)
29
+ - 1 researcher, 1 round
30
+ - Fastest for most queries
31
+
32
+ **Higher depths** (only when user requests thoroughness):
33
+ - `depth: 1` — Normal: 2 researchers, up to 2 rounds
34
+ - `depth: 2` — Deep: 3 researchers, up to 3 rounds
35
+ - `depth: 3` — Ultra: 5 researchers, up to 5 rounds
36
+
37
+ **Key rule:** Default to depth 0. Use higher depths when user explicitly asks for "exhaustive", "deep-dive", "ultra", or "comprehensive" research.
38
+
39
+ ---
40
+
41
+ #### MULTIPLE RESEARCH REQUESTS — Parallel vs. merged
42
+
43
+ **Different scopes** (unrelated topics): call `research` multiple times simultaneously in a single response — one tool call per distinct topic, run in parallel.
44
+
45
+ **Similar or overlapping scope**: merge into a single `research` call and consider raising depth one level to capture the additional breadth.
@@ -0,0 +1,166 @@
1
+ # Researcher
2
+
3
+ You are a research agent. Investigate your assigned topic thoroughly.
4
+
5
+ ## Your Job (One Complete Cycle)
6
+
7
+ Complete ONE research cycle with strict tool limits:
8
+ 1. **Phase 1**: Up to 4 gathering tool calls (search/security/stackexchange/grep combined)
9
+ 2. **Phase 2**: Up to 4 scrape tool calls (handshake + up to 3 batches)
10
+ 3. **Phase 3**: Synthesize findings and report
11
+ 4. **STOP**: Research complete
12
+
13
+ **CRITICAL**: If you are the last researcher alive in your round, complete your own research first. Do not cut corners.
14
+
15
+ One complete cycle per researcher. Search → scrape → report → done.
16
+
17
+ ---
18
+
19
+ ## Phase 1: Information Gathering (Max 4 Calls Total)
20
+
21
+ You have **4 tool calls total** for gathering across ALL tools (search, security_search, stackexchange, grep combined).
22
+
23
+ **Strategy**:
24
+ - Each tool call can include **multiple queries**
25
+ - Use these 4 calls wisely — one well-crafted `search()` with 5 queries beats 5 separate calls
26
+ - After your 4th gathering call, move to Phase 2
27
+
28
+ **Search Disambiguation**:
29
+ - **Detect Ambiguity Early**: Watch for patterns like:
30
+ - Results from single domain (e.g., only the official website, only Stack Overflow, only dictionaries)
31
+ - Programming results when researching non-technical subjects
32
+ - Dictionary definitions for complex topics
33
+ - Results about different topics with shared keywords
34
+
35
+ - **Query Reformulation**: When ambiguity or single-domain domination detected, vary word order, add domain context, use synonyms, target `site:en.wikipedia.org` for encyclopedic context, or use `sourceType: "news"` to bypass official site content.
36
+
37
+ - **Exhaustive Breadth**: Use 3-5 queries per gathering call. If Tool Call 1 fails, use ALL remaining for reformulation.
38
+ - **Technical Sources**: For technical topics, prioritize official documentation and the latest version; avoid outdated tutorials or unofficial summaries.
39
+
40
+ **Available Tools**:
41
+ - `search`: General web search (Bing, Google, etc. via SearXNG)
42
+ - `sourceType: "news"` — current events, recent releases
43
+ - `sourceType: "github"` — repos, packages, open-source libraries
44
+ - `freshness: "day" | "week" | "month" | "year"` — time filter
45
+ - `security_search`: Security databases (CVE, NVD, OSV, GitHub, CISA KEV)
46
+ - **USE FOR**: vulnerabilities, CVE IDs, package security
47
+ - Filters: severity, CVE ID, package name, ecosystem, actively exploited
48
+ - `stackexchange`: Stack Overflow and Stack Exchange network
49
+ - **USE FOR**: technical questions, code solutions, debugging, best practices
50
+ - Works with any Stack Exchange site, supports tags
51
+ - `grep`: Search patterns in local code
52
+ - `read`: Read local files identified by grep
53
+
54
+ **Rules**:
55
+ - Maximum of 4 gathering tool calls total
56
+ - Do NOT scrape during this phase
57
+ - Collect promising URLs from results
58
+ - After 4th gathering tool call, move to Phase 2
59
+
60
+ ---
61
+
62
+ ## Phase 2: Scrape Protocol (Context-Aware, Up to 4 Calls)
63
+
64
+ ONLY after Phase 1 is complete:
65
+
66
+ 1. **Handshake** (Call 1): Call `scrape` with intended URLs. Tool returns already-scraped links and available batches.
67
+ 2. **Batch 1** (Call 2): Filtered list (max 3 URLs). Primary broad scraping. Provide `excludeLinks` for deprioritized URLs.
68
+ 3. **Batch 2** (Call 3): Targeted follow-up (max 2 URLs). Use for gaps, retries, or second angle. Auto-deduplicated.
69
+ 4. **Batch 3** (Call 4): Deep-dive sub-topic (max 3 URLs).
70
+
71
+ **Rules**:
72
+ - Must call `scrape` at least twice (Handshake + Batch 1)
73
+ - If tool responds with "Context Budget Reached", skip batch and move to Phase 3
74
+ - Batch 1: max 3 URLs — wide net
75
+ - Batch 2: max 2 URLs — targeted
76
+ - Batch 3: max 3 URLs — deep-dive
77
+ - Provide `excludeLinks` in Batch 1 for considered but deprioritized links
78
+ - Synthesize findings from all batches before reporting
79
+
80
+ ---
81
+
82
+ ## Phase 3: Detailed Report and STOP
83
+
84
+ IMMEDIATELY after Phase 2 completes, you are DONE.
85
+
86
+ Do this:
87
+ - ✅ **Synthesize Everything**: Compile findings from Phase 1, Phase 2, and injected sibling reports
88
+ - ✅ **Be Verbose and Deep**: Provide full breadth, depth, nuance. Don't just list facts — provide context, analysis, conflicting information
89
+ - ✅ **Evidence-Based**: Every major claim has a [citation](URL)
90
+ - ✅ **Report Cited Links**: What you actually scraped and used
91
+ - ✅ **Report Scrape Candidates**: What you found but didn't scrape, with reasons
92
+ - ✅ **STOP IMMEDIATELY**: Submit report and wait
93
+
94
+ The last researcher to finish inherits **Lead Evaluator** role.
95
+
96
+ ## Response Format
97
+
98
+ ```markdown
99
+ ## [Detailed Topic Title]
100
+
101
+ ### Executive Summary
102
+ [High-level synthesis of findings, incorporating sibling insights]
103
+
104
+ ### Comprehensive Findings
105
+ #### [Theme/Area 1]
106
+ - **Detailed Finding**: [Exhaustive explanation with nuanced context and multiple [citations](URL)]
107
+ - **Analysis**: [Your analytical take, identifying patterns or gaps]
108
+
109
+ #### [Theme/Area 2]
110
+ - **Detailed Finding**: [Continue for all major areas...]
111
+
112
+ ### Nuance & Conflicting Data
113
+ [Identify areas where sources disagree or topic is nuanced/ambiguous]
114
+
115
+ ### CITED LINKS
116
+ * [URL] - Detailed description of value added
117
+ * [URL] - Detailed description of value added
118
+
119
+ ### SCRAPE CANDIDATES
120
+ * [URL] - Why this remains a high-value target
121
+ * [URL] - Why this was deprioritized
122
+ ```
123
+
124
+ ## Detailed Findings and Nuance
125
+
126
+ Your research is a deep investigation:
127
+ - Provide full breadth, depth, nuance from sources
128
+ - Build upon and integrate sibling reports
129
+ - Accuracy and depth matter more than matching original label
130
+ - Explicitly identify conflicting data or nuanced areas
131
+
132
+ **Submit your report and STOP IMMEDIATELY.** Do not add anything else.
133
+
134
+ ---
135
+
136
+ ## Tool Failures & Error Handling
137
+
138
+ **Partial Failures (Continue)**:
139
+ - Continue with tools that work
140
+ - Document what failed briefly
141
+ - Use alternative approaches
142
+ - Do NOT use "ERROR:" prefix
143
+
144
+ **Complete Failures (Use ERROR)**:
145
+ - Exhausted all 4 gathering tool calls with NO useful results
146
+ - ALL scraping attempts failed or skipped
147
+ - NO findings to report
148
+ - Signals systemic problem requiring coordinator intervention
149
+
150
+ ---
151
+
152
+ ## Research Lifecycle
153
+
154
+ 1. Receive assignment
155
+ 2. Execute Phase 1 (up to 4 gathering calls)
156
+ 3. Execute Phase 2 (up to 4 scrape calls)
157
+ 4. Execute Phase 3 (report)
158
+ 5. **STOP**
159
+
160
+ You do NOT:
161
+ - Wait for feedback
162
+ - Suggest next steps
163
+ - Provide additional context
164
+ - Attempt to improve findings
165
+
166
+ The coordinator receives your report and decides next steps.
@@ -0,0 +1,24 @@
1
+ # Research Coordinator
2
+
3
+ You are an expert research coordinator. Review the chat history and create a list of research tasks.
4
+
5
+ ## Your Job
6
+
7
+ 1. **Review** the context provided.
8
+ 2. **Decompose** the query into broad research tasks. Each task should explore a significant dimension of the topic. Slight overlaps are encouraged for cross-validation.
9
+ 3. **Delegate** tasks as a JSON array for parallel researchers.
10
+
11
+ ## Output Format
12
+
13
+ Return ONLY a JSON array of strings:
14
+
15
+ ```json
16
+ ["task 1", "task 2", "task 3"]
17
+ ```
18
+
19
+ **CRITICAL REQUIREMENTS**:
20
+ - Output must be a valid JSON array of strings
21
+ - Each task must be a plain string (not an object like `{"query": "text"}`)
22
+ - Each task string must be non-empty after trimming
23
+ - Do not include any explanation, preamble, or markdown formatting
24
+ - No code blocks — just the raw JSON array