@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.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/config/searxng/default-settings.yml +189 -0
- package/config/searxng/limiter.toml +34 -0
- package/config/tooling/eslint.config.js +73 -0
- package/config/tooling/vitest.config.integration.ts +17 -0
- package/config/tooling/vitest.config.ts +40 -0
- package/config/tooling/vitest.config.unit.ts +12 -0
- package/docs/ARCHITECTURE.md +109 -0
- package/docs/assets/README-banner.jpg +0 -0
- package/package.json +92 -0
- package/scripts/setup.js +174 -0
- package/src/config.ts +206 -0
- package/src/constants.ts +148 -0
- package/src/healthcheck/index.ts +309 -0
- package/src/index.ts +71 -0
- package/src/infrastructure/searxng-lifecycle.ts +577 -0
- package/src/infrastructure/searxng-manager.ts +1173 -0
- package/src/infrastructure/state-manager.ts +918 -0
- package/src/logger.ts +246 -0
- package/src/orchestration/deep-research-orchestrator.ts +848 -0
- package/src/orchestration/deep-research-reducer.ts +129 -0
- package/src/orchestration/deep-research-types.ts +54 -0
- package/src/orchestration/id-utils.ts +63 -0
- package/src/orchestration/researcher.ts +104 -0
- package/src/orchestration/session-context.ts +43 -0
- package/src/prompts/research-tool-usage.md +45 -0
- package/src/prompts/researcher.md +166 -0
- package/src/prompts/system-coordinator.md +24 -0
- package/src/prompts/system-lead-evaluator.md +225 -0
- package/src/security/cisa-kev.ts +242 -0
- package/src/security/github-advisories.ts +607 -0
- package/src/security/index.ts +406 -0
- package/src/security/nvd.ts +532 -0
- package/src/security/osv.ts +487 -0
- package/src/security/types.ts +138 -0
- package/src/stackexchange/cache.ts +111 -0
- package/src/stackexchange/index.ts +352 -0
- package/src/stackexchange/output/compact.ts +64 -0
- package/src/stackexchange/output/index.ts +7 -0
- package/src/stackexchange/output/json.ts +21 -0
- package/src/stackexchange/output/table.ts +123 -0
- package/src/stackexchange/queries.ts +168 -0
- package/src/stackexchange/rest-client.ts +127 -0
- package/src/stackexchange/types.ts +129 -0
- package/src/tool.ts +430 -0
- package/src/tools/grep.ts +335 -0
- package/src/tools/index.ts +77 -0
- package/src/tools/scrape.ts +451 -0
- package/src/tools/search.ts +188 -0
- package/src/tools/security.ts +292 -0
- package/src/tools/stackexchange.ts +101 -0
- package/src/tui/research-panel.ts +576 -0
- package/src/tui/searxng-status.ts +80 -0
- package/src/types/extension-context.ts +60 -0
- package/src/types/llm.ts +111 -0
- package/src/utils/inject-date.ts +29 -0
- package/src/utils/input-validation.ts +103 -0
- package/src/utils/json-utils.ts +262 -0
- package/src/utils/make-resource-loader.ts +43 -0
- package/src/utils/research-error.ts +205 -0
- package/src/utils/research-export.ts +199 -0
- package/src/utils/searxng-config.ts +94 -0
- package/src/utils/session-state.ts +295 -0
- package/src/utils/shared-links.ts +123 -0
- package/src/utils/shutdown-manager.ts +54 -0
- package/src/utils/text-utils.ts +83 -0
- package/src/utils/tool-usage-tracker.ts +135 -0
- package/src/web-research/dependencies.ts +20 -0
- package/src/web-research/retry-utils.ts +232 -0
- package/src/web-research/scrapers.ts +935 -0
- package/src/web-research/search.ts +235 -0
- package/src/web-research/types.ts +47 -0
- package/src/web-research/utils.ts +158 -0
- package/tsconfig.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lincoln504
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<a href="https://github.com/Lincoln504/pi-research/actions/workflows/ci.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/Lincoln504/pi-research/ci.yml?style=flat-square&branch=main" /></a> <a href="https://www.npmjs.com/package/@lincoln504/pi-research"><img alt="npm version" src="https://img.shields.io/npm/v/@lincoln504/pi-research.svg?style=flat-square" /></a>
|
|
4
|
+
|
|
5
|
+
Multi-agent web research extension for [pi](https://github.com/badlogic/pi-mono). Runs parallel AI researchers against a self-hosted SearXNG search container, scrapes pages, queries security databases, and tracks everything in a real-time terminal UI.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
- [Capabilities](#capabilities)
|
|
12
|
+
- [Requirements](#requirements)
|
|
13
|
+
- [Install](#install)
|
|
14
|
+
- [Platform Setup](#platform-setup)
|
|
15
|
+
- [Usage](#usage)
|
|
16
|
+
- [Research Depth](#research-depth)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Development & Release](#development--release)
|
|
19
|
+
- [Architecture & Design](docs/ARCHITECTURE.md)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Capabilities
|
|
24
|
+
|
|
25
|
+
- **Multi-agent deep research** — AI coordinator decomposes a query into parallel research tracks; an AI lead evaluator synthesizes or delegates further rounds
|
|
26
|
+
- **Quick mode** — single researcher for fast, focused queries with no coordinator overhead
|
|
27
|
+
- **Web search** — SearXNG running in Docker, aggregating Bing, Brave, Yahoo, Qwant, DuckDuckGo, Wikipedia, GitHub, arXiv, and Semantic Scholar (engines can be enabled or disabled via [config](docs/ARCHITECTURE.md#searxng-lifecycle-management))
|
|
28
|
+
- **URL scraping** — fetch-first with Playwright/Chromium fallback for JavaScript-heavy pages
|
|
29
|
+
- **Security databases** — NVD, CISA KEV, GitHub Advisories, OSV
|
|
30
|
+
- **Stack Exchange** — full network search and filtering
|
|
31
|
+
- **Real-time TUI** — per-researcher token and cost tracking
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
── Research: 70% ─────────────────────────────────────
|
|
35
|
+
┌───────┬────┐ 1 ┌─────┬────┐ 2 ┌────┬────┐ 3 ┌────┐
|
|
36
|
+
│SearXNG│ 18k │ 36k │ 50k │
|
|
37
|
+
│:55732 │ $0.0056 │ $0.0055 │ $0.0071 │
|
|
38
|
+
└───────┴──────────────┴─────────────┴─────────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Node.js `22.13.0` or any `24.x+` release
|
|
47
|
+
- The `pi` CLI installed and configured
|
|
48
|
+
- Docker daemon running (required for SearXNG)
|
|
49
|
+
- Internet access
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pi install npm:@lincoln504/pi-research
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**From a checkout**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install
|
|
63
|
+
pi install .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Platform Setup
|
|
69
|
+
|
|
70
|
+
**macOS/Linux** — Install and start Docker. Ensure your user is in the `docker` group on Linux.
|
|
71
|
+
**Windows** — Install Docker Desktop (Linux containers). Detecting named pipes is automatic.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
Ask pi for web research. The extension registers a `research` tool.
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
Research "What is a binary search tree?"
|
|
81
|
+
Do a deep dive on CVE-2024-3094 at depth 2
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Depth | Mode | Researchers | Target rounds |
|
|
85
|
+
|-------|------|-------------|---------------|
|
|
86
|
+
| 0 (default) | Quick | 1 | 1 |
|
|
87
|
+
| 1 | Normal | 2 | 2 |
|
|
88
|
+
| 2 | Deep | 3 | 3 |
|
|
89
|
+
| 3 | Ultra | 5 | 5 |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
| Variable | Default | Description |
|
|
96
|
+
|----------|---------|-------------|
|
|
97
|
+
| `BRAVE_SEARCH_API_KEY` | — | Enables `braveapi` engine (official REST API) |
|
|
98
|
+
| `PI_RESEARCH_VERBOSE` | — | Set to `1` to write diagnostic JSONL logs to a temp file (see below) |
|
|
99
|
+
| `PI_RESEARCH_SKIP_HEALTHCHECK` | — | Skip startup health check (set to `1` if engines are blocked) |
|
|
100
|
+
| `PROXY_URL` | — | Proxy for SearXNG outgoing requests (e.g. `socks5://127.0.0.1:9050`) |
|
|
101
|
+
| `STACKEXCHANGE_API_KEY` | — | Stack Exchange API key (increases limit from 300 to 10,000/day) |
|
|
102
|
+
| `PI_RESEARCH_SEARCH_LANGUAGE` | `en-US` | BCP 47 language tag for search result filtering |
|
|
103
|
+
| `PI_RESEARCH_RESEARCHER_TIMEOUT_MS` | `240000` | Per-researcher timeout (30s to 10m) |
|
|
104
|
+
| `PI_RESEARCH_MAX_CONCURRENT_RESEARCHERS` | `3` | Maximum researchers running simultaneously (1 to 10) |
|
|
105
|
+
| `PI_RESEARCH_CONSOLE_RESTORE_DELAY_MS` | `15000` | Delay before TUI clears after research ends |
|
|
106
|
+
| `SEARXNG_IMAGE_TAG` | `latest` | SearXNG Docker image tag — pin to a specific release for reproducibility (e.g. `2024.12.23`) |
|
|
107
|
+
|
|
108
|
+
**Verbose logging**
|
|
109
|
+
|
|
110
|
+
Set `PI_RESEARCH_VERBOSE=1` (or pass `--verbose`) to enable diagnostic output. Logs are written as JSONL to `{os.tmpdir()}/pi-research-debug-{hash}.log` — one file per session, never written to stdout. Each log line includes a session correlation ID so multiple concurrent sessions are distinguishable. The log path is printed to stderr on startup when verbose mode is active.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Development & Release
|
|
115
|
+
|
|
116
|
+
**Commands**
|
|
117
|
+
- `npm run lint` / `npm run lint:fix`: Code quality
|
|
118
|
+
- `npm run type-check`: TypeScript verification
|
|
119
|
+
- `npm run test:unit`: Unit tests — no dependencies
|
|
120
|
+
- `npm run test:integration`: Integration tests — requires Docker; uses Testcontainers to spin up a real SearXNG instance (runs locally and in CI)
|
|
121
|
+
|
|
122
|
+
**Release**
|
|
123
|
+
1. `npm version patch` (or minor/major)
|
|
124
|
+
2. `git push origin main --tags`
|
|
125
|
+
The GitHub Action will automatically publish to npm and create a release.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Architecture
|
|
130
|
+
|
|
131
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for detailed design information.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# SearXNG Default Configuration for pi-search-scrape Extension
|
|
2
|
+
# IMPROVED: Better timeouts, removed problematic engines, added real user agent
|
|
3
|
+
|
|
4
|
+
general:
|
|
5
|
+
instance_name: "pi SearXNG"
|
|
6
|
+
debug: false
|
|
7
|
+
privacypolicy_url: false
|
|
8
|
+
contact_url: false
|
|
9
|
+
enable_metrics: true # ENABLED for debugging engine issues
|
|
10
|
+
open_metrics: ''
|
|
11
|
+
|
|
12
|
+
brand:
|
|
13
|
+
new_issue_url: https://github.com/searxng/searxng/issues/new
|
|
14
|
+
docs_url: https://docs.searxng.org/
|
|
15
|
+
public_instances: https://searx.space
|
|
16
|
+
wiki_url: https://github.com/searxng/searxng/wiki
|
|
17
|
+
issue_url: https://github.com/searxng/searxng/issues
|
|
18
|
+
|
|
19
|
+
server:
|
|
20
|
+
port: 8080
|
|
21
|
+
bind_address: "0.0.0.0"
|
|
22
|
+
secret_key: ""
|
|
23
|
+
base_url: false
|
|
24
|
+
limiter: false
|
|
25
|
+
public_instance: false
|
|
26
|
+
image_proxy: false
|
|
27
|
+
http_protocol_version: "1.1"
|
|
28
|
+
method: "GET"
|
|
29
|
+
default_http_headers:
|
|
30
|
+
# REAL BROWSER USER AGENT - prevents bot detection
|
|
31
|
+
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
32
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
|
|
33
|
+
Accept-Language: "en-US,en;q=0.9"
|
|
34
|
+
Accept-Encoding: "gzip, deflate, br"
|
|
35
|
+
X-Content-Type-Options: nosniff
|
|
36
|
+
X-Download-Options: noopen
|
|
37
|
+
X-Robots-Tag: noindex, nofollow
|
|
38
|
+
Referrer-Policy: no-referrer
|
|
39
|
+
|
|
40
|
+
search:
|
|
41
|
+
safe_search: 1
|
|
42
|
+
autocomplete: ""
|
|
43
|
+
autocomplete_min: 4
|
|
44
|
+
favicon_resolver: ""
|
|
45
|
+
default_lang: "en-US"
|
|
46
|
+
ban_time_on_fail: 5
|
|
47
|
+
max_ban_time_on_fail: 120
|
|
48
|
+
formats:
|
|
49
|
+
- html
|
|
50
|
+
- json
|
|
51
|
+
- csv
|
|
52
|
+
- rss
|
|
53
|
+
suspended_times:
|
|
54
|
+
# Long backoff prevents hammering blocked engines — re-check after 24h
|
|
55
|
+
SearxEngineAccessDenied: 86400
|
|
56
|
+
SearxEngineCaptcha: 86400
|
|
57
|
+
SearxEngineTooManyRequests: 3600
|
|
58
|
+
cf_SearxEngineCaptcha: 1296000
|
|
59
|
+
cf_SearxEngineAccessDenied: 86400
|
|
60
|
+
recaptcha_SearxEngineCaptcha: 604800
|
|
61
|
+
|
|
62
|
+
ui:
|
|
63
|
+
static_path: ""
|
|
64
|
+
templates_path: ""
|
|
65
|
+
query_in_title: false
|
|
66
|
+
default_theme: simple
|
|
67
|
+
center_alignment: false
|
|
68
|
+
default_locale: ""
|
|
69
|
+
results_on_new_tab: false
|
|
70
|
+
theme_args:
|
|
71
|
+
simple_style: auto
|
|
72
|
+
search_on_category_select: true
|
|
73
|
+
hotkeys: default
|
|
74
|
+
url_formatting: pretty
|
|
75
|
+
|
|
76
|
+
outgoing:
|
|
77
|
+
request_timeout: 20.0 # INCREASED from 10.0
|
|
78
|
+
max_request_timeout: 60.0 # INCREASED from 30.0
|
|
79
|
+
useragent_suffix: ""
|
|
80
|
+
pool_connections: 200 # INCREASED from 150
|
|
81
|
+
pool_maxsize: 30 # INCREASED from 20
|
|
82
|
+
enable_http2: true # ENABLED (was false)
|
|
83
|
+
retries: 3 # INCREASED from 2
|
|
84
|
+
using_tor_proxy: false
|
|
85
|
+
extra_proxy_timeout: 15
|
|
86
|
+
|
|
87
|
+
doi_resolvers:
|
|
88
|
+
oadoi.org: 'https://oadoi.org/'
|
|
89
|
+
doi.org: 'https://doi.org/'
|
|
90
|
+
default_doi_resolver: 'oadoi.org'
|
|
91
|
+
|
|
92
|
+
# Search engines configuration
|
|
93
|
+
#
|
|
94
|
+
# Engine reliability for a private low-volume self-hosted instance (2026):
|
|
95
|
+
# Bing — most consistently available; scrapes bing.com directly; weak on ambiguous queries
|
|
96
|
+
# Brave — independent index; moderate bot detection; occasional suspension at burst rates
|
|
97
|
+
# Yahoo — different backend from Bing; low blocking rate; lower result quality
|
|
98
|
+
# Qwant — EU-based independent index; low-volume private use is generally fine
|
|
99
|
+
# DuckDuckGo — ddg-lite endpoint (no vqd); intermittent IP blocks (issue #4824, open)
|
|
100
|
+
# StartPage — DISABLED: broken in current SearXNG due to missing sgt param (issue #4549, open)
|
|
101
|
+
# Google — DISABLED: IP-blocks any nontrivial automated use
|
|
102
|
+
#
|
|
103
|
+
# If BRAVE_SEARCH_API_KEY is set, searxng-lifecycle.ts injects a braveapi engine at weight 1.2
|
|
104
|
+
# which uses the official REST API and is not subject to bot detection.
|
|
105
|
+
|
|
106
|
+
engines:
|
|
107
|
+
# Bing: most reliable free general-web engine for private instances at low volume
|
|
108
|
+
- name: bing
|
|
109
|
+
engine: bing
|
|
110
|
+
shortcut: bi
|
|
111
|
+
weight: 1.5
|
|
112
|
+
|
|
113
|
+
# Brave (scraping): independent index, different coverage from Bing
|
|
114
|
+
# Can enter suspension after bursts; max_page 10 respected by SearXNG
|
|
115
|
+
- name: brave
|
|
116
|
+
engine: brave
|
|
117
|
+
shortcut: bv
|
|
118
|
+
weight: 0.8
|
|
119
|
+
|
|
120
|
+
# Yahoo: distinct backend, low blocking rate, fills gaps when others are suspended
|
|
121
|
+
- name: yahoo
|
|
122
|
+
engine: yahoo
|
|
123
|
+
shortcut: yh
|
|
124
|
+
weight: 0.8
|
|
125
|
+
|
|
126
|
+
# Qwant: EU-based independent index, low-volume private use stable
|
|
127
|
+
- name: qwant
|
|
128
|
+
engine: qwant
|
|
129
|
+
shortcut: qw
|
|
130
|
+
weight: 0.7
|
|
131
|
+
|
|
132
|
+
# DuckDuckGo: ddg-lite endpoint (no vqd); intermittent IP blocks (issue #4824 open)
|
|
133
|
+
- name: duckduckgo
|
|
134
|
+
engine: duckduckgo
|
|
135
|
+
shortcut: ddg
|
|
136
|
+
weight: 0.6
|
|
137
|
+
|
|
138
|
+
# DISABLED: startpage — sgt parameter missing in SearXNG parser (issue #4549, open)
|
|
139
|
+
# DISABLED: google — IP-blocks automated access within minutes
|
|
140
|
+
|
|
141
|
+
# Wikipedia: Encyclopedic reference
|
|
142
|
+
# - Reliability: HIGH (uses REST API)
|
|
143
|
+
# - Note: Keep weight low to prioritize search engines
|
|
144
|
+
- name: wikipedia
|
|
145
|
+
engine: wikipedia
|
|
146
|
+
shortcut: wp
|
|
147
|
+
categories: [general]
|
|
148
|
+
weight: 0.3 # LOWER - reference only, not primary search
|
|
149
|
+
|
|
150
|
+
# Images (only when category=images is requested)
|
|
151
|
+
- name: bing images
|
|
152
|
+
engine: bing_images
|
|
153
|
+
categories: [images]
|
|
154
|
+
shortcut: bii
|
|
155
|
+
|
|
156
|
+
# News (only when category=news is requested)
|
|
157
|
+
- name: bing news
|
|
158
|
+
engine: bing_news
|
|
159
|
+
categories: [news]
|
|
160
|
+
shortcut: bin
|
|
161
|
+
|
|
162
|
+
# REMOVED: brave_news (engine not available in SearXNG container)
|
|
163
|
+
|
|
164
|
+
# Videos (only when category=videos is requested)
|
|
165
|
+
- name: bing videos
|
|
166
|
+
engine: bing_videos
|
|
167
|
+
categories: [videos]
|
|
168
|
+
shortcut: biv
|
|
169
|
+
|
|
170
|
+
# Technical/IT (only when category=it is requested)
|
|
171
|
+
# REMOVED: stackoverflow (engine not available in SearXNG container)
|
|
172
|
+
- name: github
|
|
173
|
+
engine: github
|
|
174
|
+
categories: [it]
|
|
175
|
+
shortcut: gh
|
|
176
|
+
weight: 1.0
|
|
177
|
+
|
|
178
|
+
# Science/Academic (only when category=science is requested)
|
|
179
|
+
- name: arxiv
|
|
180
|
+
engine: arxiv
|
|
181
|
+
categories: [science]
|
|
182
|
+
weight: 1.5 # INCREASED
|
|
183
|
+
shortcut: arx
|
|
184
|
+
|
|
185
|
+
- name: semantic scholar
|
|
186
|
+
engine: semantic_scholar
|
|
187
|
+
categories: [science]
|
|
188
|
+
weight: 1.5 # INCREASED
|
|
189
|
+
shortcut: sem
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# SearXNG Limiter Configuration for pi-search-scrape
|
|
2
|
+
# This configuration disables all bot detection and rate limiting for local use
|
|
3
|
+
|
|
4
|
+
[botdetection]
|
|
5
|
+
# The prefix defines number of leading bits in an address that are compared
|
|
6
|
+
# to determine whether or not an address is part of a (client) network.
|
|
7
|
+
ipv4_prefix = 32
|
|
8
|
+
ipv6_prefix = 48
|
|
9
|
+
|
|
10
|
+
# Trust localhost requests completely (no bot detection for local connections)
|
|
11
|
+
trusted_proxies = [
|
|
12
|
+
'127.0.0.0/8',
|
|
13
|
+
'::1',
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[botdetection.ip_limit]
|
|
17
|
+
# Disable rate limiting for link-local addresses (localhost)
|
|
18
|
+
filter_link_local = false
|
|
19
|
+
# Disable link token method (no captcha required)
|
|
20
|
+
link_token = false
|
|
21
|
+
|
|
22
|
+
[botdetection.ip_lists]
|
|
23
|
+
# No IP blocking for local use
|
|
24
|
+
block_ip = []
|
|
25
|
+
|
|
26
|
+
# Allow all localhost requests without restrictions
|
|
27
|
+
pass_ip = [
|
|
28
|
+
'127.0.0.0/8', # IPv4 localhost
|
|
29
|
+
'fe80::/10', # IPv6 link-local
|
|
30
|
+
'0.0.0.0/0', # Allow all IPv4 (for local container use)
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# Allow SearXNG org IPs for checks
|
|
34
|
+
pass_searxng_org = true
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
3
|
+
import tsparser from '@typescript-eslint/parser';
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
// Global ignores
|
|
7
|
+
{
|
|
8
|
+
ignores: [
|
|
9
|
+
'node_modules/**',
|
|
10
|
+
'dist/**',
|
|
11
|
+
'*.d.ts',
|
|
12
|
+
'examples/**',
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
// JavaScript recommended rules
|
|
16
|
+
js.configs.recommended,
|
|
17
|
+
// TypeScript recommended rules
|
|
18
|
+
{
|
|
19
|
+
files: ['**/*.ts'],
|
|
20
|
+
languageOptions: {
|
|
21
|
+
parser: tsparser,
|
|
22
|
+
parserOptions: {
|
|
23
|
+
ecmaVersion: 2022,
|
|
24
|
+
sourceType: 'module',
|
|
25
|
+
project: './tsconfig.json',
|
|
26
|
+
},
|
|
27
|
+
globals: {
|
|
28
|
+
process: 'readonly',
|
|
29
|
+
console: 'readonly',
|
|
30
|
+
Buffer: 'readonly',
|
|
31
|
+
__dirname: 'readonly',
|
|
32
|
+
__filename: 'readonly',
|
|
33
|
+
require: 'readonly',
|
|
34
|
+
module: 'readonly',
|
|
35
|
+
exports: 'readonly',
|
|
36
|
+
NodeJS: 'readonly',
|
|
37
|
+
setTimeout: 'readonly',
|
|
38
|
+
setInterval: 'readonly',
|
|
39
|
+
clearTimeout: 'readonly',
|
|
40
|
+
clearInterval: 'readonly',
|
|
41
|
+
crypto: 'readonly',
|
|
42
|
+
AbortSignal: 'readonly',
|
|
43
|
+
AbortController: 'readonly',
|
|
44
|
+
Request: 'readonly',
|
|
45
|
+
RequestInit: 'readonly',
|
|
46
|
+
Response: 'readonly',
|
|
47
|
+
FormData: 'readonly',
|
|
48
|
+
fetch: 'readonly',
|
|
49
|
+
URL: 'readonly',
|
|
50
|
+
URLSearchParams: 'readonly',
|
|
51
|
+
ArrayBuffer: 'readonly',
|
|
52
|
+
ReadableStream: 'readonly',
|
|
53
|
+
Blob: 'readonly',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
plugins: {
|
|
57
|
+
'@typescript-eslint': tseslint,
|
|
58
|
+
},
|
|
59
|
+
rules: {
|
|
60
|
+
// Override specific rules
|
|
61
|
+
'no-console': 'off', // Allow console.log for debugging
|
|
62
|
+
'no-unused-vars': 'off', // Disable in favor of TypeScript version
|
|
63
|
+
'@typescript-eslint/no-unused-vars': [
|
|
64
|
+
'error',
|
|
65
|
+
{
|
|
66
|
+
argsIgnorePattern: '^_',
|
|
67
|
+
varsIgnorePattern: '^_',
|
|
68
|
+
caughtErrorsIgnorePattern: '^_',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import baseConfig from './vitest.config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
...baseConfig,
|
|
6
|
+
test: {
|
|
7
|
+
...baseConfig.test,
|
|
8
|
+
// Integration tests using testcontainers
|
|
9
|
+
include: ['test/integration/**/*.test.ts'],
|
|
10
|
+
setupFiles: [],
|
|
11
|
+
testTimeout: 180000, // 180 second timeout for integration tests
|
|
12
|
+
maxConcurrency: 1, // Only one integration test at a time due to containers
|
|
13
|
+
fileParallelism: false,
|
|
14
|
+
pool: 'forks',
|
|
15
|
+
hookTimeout: 60000,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
test: {
|
|
9
|
+
globals: true,
|
|
10
|
+
environment: 'node',
|
|
11
|
+
include: ['**/*.test.ts', '**/*.spec.ts'],
|
|
12
|
+
exclude: ['node_modules', 'dist', '.tmp'],
|
|
13
|
+
coverage: {
|
|
14
|
+
provider: 'v8',
|
|
15
|
+
reporter: ['text', 'json', 'html', 'lcov'],
|
|
16
|
+
exclude: [
|
|
17
|
+
'node_modules/',
|
|
18
|
+
'dist/',
|
|
19
|
+
'**/*.test.ts',
|
|
20
|
+
'**/*.spec.ts',
|
|
21
|
+
'**/types.ts',
|
|
22
|
+
'**/index.ts',
|
|
23
|
+
'test/',
|
|
24
|
+
],
|
|
25
|
+
reportOnFailure: true,
|
|
26
|
+
},
|
|
27
|
+
testTimeout: 60000,
|
|
28
|
+
hookTimeout: 30000,
|
|
29
|
+
teardownTimeout: 10000,
|
|
30
|
+
pool: 'threads',
|
|
31
|
+
includeSource: ['src/**/*.ts'],
|
|
32
|
+
setupFiles: ['./test/setup/unit.ts'],
|
|
33
|
+
},
|
|
34
|
+
resolve: {
|
|
35
|
+
alias: {
|
|
36
|
+
'@': path.resolve(__dirname, './src'),
|
|
37
|
+
'@test': path.resolve(__dirname, './test'),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import baseConfig from './vitest.config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
...baseConfig,
|
|
6
|
+
test: {
|
|
7
|
+
...baseConfig.test,
|
|
8
|
+
include: ['test/unit/**/*.test.ts'],
|
|
9
|
+
setupFiles: ['./test/setup/unit.ts'],
|
|
10
|
+
testTimeout: 10000,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Orchestration Modes
|
|
4
|
+
|
|
5
|
+
Two primary modes: **Quick Mode** and **Deep Mode**.
|
|
6
|
+
|
|
7
|
+
### Quick Mode
|
|
8
|
+
Routes research tasks to a single **Agent Researcher** session. No coordination or evaluation overhead — suitable for focused queries.
|
|
9
|
+
|
|
10
|
+
### Deep Mode
|
|
11
|
+
Uses a state machine to manage a three-status research lifecycle:
|
|
12
|
+
|
|
13
|
+
1. **Planning Status**: The AI coordinator analyzes the conversation context and generates a JSON-formatted research agenda—a list of high-level research tasks.
|
|
14
|
+
2. **Researching Status**:
|
|
15
|
+
- **Parallel Execution**: **Agent Researchers** run in parallel (up to 3 concurrent). Each researcher handles one agenda task per round.
|
|
16
|
+
- **Report Injection**: Collective knowledge is managed by the orchestrator. When a researcher completes its task, its full report (up to 50k chars) is **injected** into the context of siblings starting later, or **steered** into already running ones. This ensures researchers don't just know *what* was scraped, but also *what was found*.
|
|
17
|
+
- **Lead Evaluation**: When a round is complete, a **Lead Evaluator** agent call is triggered. It reviews all accumulated findings against the original agenda.
|
|
18
|
+
- **Decision Outcome**: The evaluator makes a binary choice:
|
|
19
|
+
- **Synthesize**: Generate a final, exhaustive Markdown report (transition to **Completed**).
|
|
20
|
+
- **Delegate**: Formulate new, targeted queries for a subsequent round (remain in **Researching**).
|
|
21
|
+
3. **Completed Status**: The final synthesis is returned as the tool result.
|
|
22
|
+
|
|
23
|
+
State transitions are managed by a pure reducer (`src/orchestration/deep-research-reducer.ts`), ensuring predictable behavior.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## The Agent Researcher
|
|
28
|
+
|
|
29
|
+
An **Agent Researcher** is the fundamental building block of `pi-research`. Regardless of the orchestration mode, every researcher follows a structured three-phase internal lifecycle:
|
|
30
|
+
|
|
31
|
+
### Phase 1: Gathering
|
|
32
|
+
The researcher uses broad tools to discover relevant information and identify high-quality URLs for further investigation.
|
|
33
|
+
- **Budget**: 4 Gathering calls (shared across `search`, `security_search`, `stackexchange`, and `grep`).
|
|
34
|
+
- **Goal**: Breadth-first exploration and URL discovery.
|
|
35
|
+
|
|
36
|
+
### Phase 2: Scraping
|
|
37
|
+
The researcher deep-dives into the URLs identified during the Gathering phase to extract detailed content.
|
|
38
|
+
- **Budget**: 4 Scrape calls (1 handshake + 3 execution batches).
|
|
39
|
+
- **Goal**: Depth-first extraction of specific data and evidence.
|
|
40
|
+
- **Deduplication**: Researchers check a shared URL pool to avoid re-scraping links already handled by siblings in the same operation.
|
|
41
|
+
|
|
42
|
+
### Phase 3: Reporting
|
|
43
|
+
The researcher synthesizes its individual findings into a structured Markdown report.
|
|
44
|
+
- **Structure**: Includes an executive summary, key findings, and a list of cited links.
|
|
45
|
+
- **Signaling**: Once finished, the report is submitted to the orchestrator for injection into siblings (Deep Mode) or final return (Quick Mode).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Component Details
|
|
50
|
+
|
|
51
|
+
### Research Tools & Limits
|
|
52
|
+
Each researcher session is constrained by a `ToolUsageTracker` to prevent infinite loops and manage token consumption:
|
|
53
|
+
- **search**: Interfaces with the local SearXNG instance. Supports multiple queries per call.
|
|
54
|
+
- **scrape**: Multi-batch protocol for page extraction.
|
|
55
|
+
- **security_search**: Queries NVD, CISA KEV, GitHub Advisories, and OSV.
|
|
56
|
+
- **stackexchange**: Queries the Stack Exchange network (Stack Overflow, etc.).
|
|
57
|
+
- **grep**: Local codebase search using `ripgrep` (fallback to `grep`).
|
|
58
|
+
|
|
59
|
+
### Context-Aware Scraping Protocol
|
|
60
|
+
To avoid exceeding LLM context windows, the `scrape` tool follows a four-step handshake. **Each batch step is gated by a 55% context check** — if the session token count already exceeds 55% of the model's context window, that batch is skipped entirely and the tool returns early.
|
|
61
|
+
|
|
62
|
+
1. **Handshake**: The researcher identifies target URLs. The tool returns a list of URLs already scraped by siblings. No network activity; no context check.
|
|
63
|
+
2. **Batch 1**: Up to 3 URLs — primary broad scraping.
|
|
64
|
+
3. **Batch 2**: Up to 2 URLs — targeted follow-up, deduplicated against Batch 1.
|
|
65
|
+
4. **Batch 3**: Up to 3 URLs — deep-dive scraping.
|
|
66
|
+
|
|
67
|
+
### Shared Link Deduplication
|
|
68
|
+
Researchers share a URL pool per research operation, used by the `scrape` handshake to avoid redundant network requests. The pool tracks URLs only — findings are shared separately via Report Injection. It resets for each new query.
|
|
69
|
+
|
|
70
|
+
### SearXNG Lifecycle Management
|
|
71
|
+
SearXNG runs as a Docker container (`searxng/searxng`, tag controlled by `SEARXNG_IMAGE_TAG`, default `latest`).
|
|
72
|
+
- **Lazy Initialization**: The container starts only upon the first research request.
|
|
73
|
+
- **Singleton Pattern**: A single container is shared across all pi processes on the machine. State is persisted to `~/.pi/state/searxng-singleton.json`; each pi process registers a session by PID and the container stays alive until all registered processes have exited.
|
|
74
|
+
- **Configuration**: Runtime settings (proxies, API keys) are generated dynamically and volume-mounted into the container.
|
|
75
|
+
- **Engine configuration**: Active search engines are defined in `config/searxng/default-settings.yml`. Engines can be enabled or disabled by editing that file before starting the container.
|
|
76
|
+
- **Cross-Session Persistence**: Container state and locking are managed via `~/.pi/state/searxng-singleton.json` to handle multiple concurrent pi processes.
|
|
77
|
+
|
|
78
|
+
### Output File Location
|
|
79
|
+
|
|
80
|
+
When research completes, the report is written to a `.md` file named `pi-research-{sanitized-query}-{hash}.md` (e.g. `pi-research-rust-async-runtimes-a3.md`). The destination directory is resolved from the pi session's working directory (`cwd`) using a three-tier priority:
|
|
81
|
+
|
|
82
|
+
1. **cwd is home or a system directory** → `os.tmpdir()`. Prevents cluttering `~`, drive roots, or system paths like `/usr`.
|
|
83
|
+
2. **cwd contains a recognised subdirectory** → that subdirectory. Probed in priority order: `research`, `docs`, `doc`, `ref`, `references`, `notes`. Matching is case-insensitive so it works on macOS APFS and Windows NTFS.
|
|
84
|
+
3. **Otherwise** → cwd itself.
|
|
85
|
+
|
|
86
|
+
The two-character hash suffix (`{letter}{digit}`, e.g. `b7`) is a collision guard — the file is opened with an exclusive-create flag and the hash is regenerated on `EEXIST`. The full saved path is appended as a footer in the report and returned to the pi UI.
|
|
87
|
+
|
|
88
|
+
### TUI Progress Percentage
|
|
89
|
+
|
|
90
|
+
The header percentage (`Research: 70%`) tracks tool-call units completed against a budget established after planning. The budget is set from the number of agenda items the coordinator produces — which scales with query complexity (complexity 1 → 2 initial researchers, 2 → 3, 3 → 5), each researcher allocated 10 units. The budget expands dynamically when the evaluator delegates additional rounds. If research goes beyond the planned rounds the display switches to `exploring` instead of a percentage.
|
|
91
|
+
|
|
92
|
+
### Evaluator Decision Framework
|
|
93
|
+
The Lead Evaluator follows a strict priority list:
|
|
94
|
+
1. **Error Check**: If all researchers in a round failed, it reports a critical failure and stops.
|
|
95
|
+
2. **Coverage Check**: It compares cumulative findings against the initial agenda items.
|
|
96
|
+
3. **Round Budget**: It checks the round budget (`targetRounds + MAX_EXTRA_ROUNDS`). The hard limit is `targetRounds + 2` bonus rounds.
|
|
97
|
+
4. **Action Selection**: Produces either a Markdown synthesis (final result) or a JSON delegation object (`{"action": "delegate", "queries": [...]}`). Any non-JSON response is treated as a final synthesis to prevent the research from getting stuck.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Project Structure
|
|
102
|
+
|
|
103
|
+
- `src/orchestration/`: Core state machine, coordinator, and evaluator logic.
|
|
104
|
+
- `src/infrastructure/`: Docker container management and SearXNG lifecycle.
|
|
105
|
+
- `src/tools/`: Implementations for search, scraping, and specialized database queries.
|
|
106
|
+
- `src/tui/`: Real-time terminal UI components using `pi`'s display capabilities.
|
|
107
|
+
- `src/utils/`: Shared utilities for token tracking, JSON extraction, and link deduplication.
|
|
108
|
+
- `src/prompts/`: Markdown-based system instructions for the Coordinator, Researcher, and Evaluator.
|
|
109
|
+
- `config/`: Default SearXNG engine and rate-limiter configurations.
|
|
Binary file
|