Skip to main content
Glama
aisearch

aisearch

by PKrokosz
README.md
# AiSearch — zamknięty ekosystem wyszukiwania + przeglądarka dla agentów

<p align="center">
  <strong>Model zgaduje adresy. HTTP je weryfikuje i naprawia. Nic nie jest prawdą, dopóki serwer tego nie potwierdzi.</strong>
</p>

<p align="center">
  <img alt="CI" src="https://github.com/PKrokosz/aisearch-engine/actions/workflows/ci.yml/badge.svg">
  <img alt="license" src="https://img.shields.io/badge/license-MIT-blue.svg">
  <img alt="node" src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg">
  <img alt="python" src="https://img.shields.io/badge/python-%3E%3D3.11-blue.svg">
  <img alt="deps" src="https://img.shields.io/badge/runtime%20deps-0-brightgreen.svg">
  <img alt="tests" src="https://img.shields.io/badge/tests-78-brightgreen.svg">
  <img alt="eval gate" src="https://img.shields.io/badge/eval%20gate-PASS-success.svg">
  <img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg">
</p>

Zamknięty ekosystem wyszukiwania dla agentów AI: **plan → propose → resolve → falsify → [SERP] → learn**, z autokorektorem (redirect/Wayback), trzema cache'ami, feedami, nauką źródeł i detektorem driftu dokumentacji. Tam gdzie tekst się nie przewija (JS, SPA), wchodzi przeglądarka **Obscura** (V8) — a werdykt zawsze zostaje po stronie silnika. Jeden serwer MCP, trzy wejścia (MCP/HTTP/CLI), zero zależności runtime.

To nie jest kopia ani „jeszcze jeden wrapper". To **synteza dwóch dojrzałych
podejść** w jednym czystym repo:

| Warstwa | Skąd | Co wzięliśmy |
|---|---|---|
| **Mózg** — pipeline `plan→propose→resolve→falsify→rank→[SERP]→learn→out`, 3 cache'e, feedindex, prior/drift, ewaluacja z bramką CI | `pkrokosz.pl/mcp/src/web/` (AiSearch) | cały rdzeń — jeden do jednego, z 49 testami i zielonym gate'm |
| **Ręce** — przeglądarka headless (38 narzędzi), render jako eskalacja | `agentmg/tools/obscura/` (Obscura) | klient MCP + polityka renderowania + passthrough narzędzi `browser_*` |
| **Interfejsy** — jeden silnik, trzy wejścia | oba źródła | MCP stdio + HTTP + CLI-bridge; sandbox Python (tylko przestrzeń `web`) |

**Bez szumu** — celowo usunięte: narzędzia YouTube (mają własne repo
`youtube-transcript-search`), przestrzenie sandboxu niebędące `web`
(posts/projects/agentmg…), zależności runtime (**zero** — `npm install` niepotrzebny),
fork SDK MCP (JSON-RPC 2.0 po liniach napisany ręcznie — 4 metody, nie biblioteka),
domeny własne w kodzie (przez `WEB_SOURCE_LOCAL`), PHP-warstwa (repo ją dostarcza
samo, jeśli chce).

## Szybki start

```bash
# 1. Bramka jakości — offline, deterministyczna (CI)
npm run eval            # replay + gate: hit_rate, repair_rate, false_positive
npm test                # wszystkie testy (Node + Python), bez sieci

# 2. Dashboard / ślad decyzji w języku naturalnym
npm run dashboard "PHP 8.4 release announcement changelog"

# 3. Serwer MCP dla agenta (opencode / Claude / inne)
#    package.json "bin": aisearch → src/mcp/server.mjs
#    albo ręcznie: node src/mcp/server.mjs
```

### Rejestracja MCP (opencode / Claude)

```json
{
  "mcpServers": {
    "aisearch": {
      "command": "node",
      "args": ["C:/Users/admin/Desktop/aisearch/src/mcp/server.mjs"]
    }
  }
}
```

### Warstwa HTTP (sandbox, debug, integracje)

```bash
npm run http                                   # http://127.0.0.1:8787
curl -H "authorization: Bearer $WEB_API_KEY" http://127.0.0.1:8787/web/stats
```

## Narzędzia (jeden serwer, dwa światy)

**Silnik (`web.*`)** — 13 narzędzi:

| Narzędzie | Po co |
|---|---|
| `web.search` | cały pipeline; wynik = ranked + provenance + ślad decyzji |
| `web.brief` | jedno wywołanie → zwinięty brief (rank/score/flags) |
| `web.verify_links` | partia kandydatów w jednym callu: survived/rejected/repaired |
| `web.drift_report` | drift dokumentacji + prior + werdykt w języku naturalnym |
| `web.render` | render jednej strony przez V8 (jawny, drogi) |
| `web.trace` | pełny ślad etapów — do debugowania „co się zadziało" |
| `web.feedback` | pętla użyteczności: used/ignored/rejected → prior |
| `web.eval` | metryki jakości + werdykt bramki (replay/live) |
| `web.stats` · `web.drift` · `web.cache` · `web.feeds` · `web.configure` | widok wnętrza ekosystemu |

**Przeglądarka (`browser_*`)** — pełny passthrough Obscury (`browser_navigate`,
`browser_markdown`, `browser_links`, `browser_click`, `browser_fill`, `browser_evaluate`,
`browser_screenshot`, `browser_pdf`, zakładki…). Lista zależy od zainstalowanej wersji
binarii. Gdy binaria nie ma — serwer i tak działa, tylko `web.*`.

## Jak współpracują mózg i ręce

```
plan → propose → resolve (fetch, redirecty, cache) → renderPass (Obscura, auto) → falsify → rank → [SERP] → learn → out
                                                    └── tylko JS-shelle: 200, ale treści < WEB_RENDER_MIN_TEXT
```

Zasady (wynikione z pułapek obu światów, opis w `docs/ARCHITECTURE.md`):
1. **Fetch zostaje na głównej ścieżce** — szybki, liczy redirecty (na nich stoi
   detektor driftu), deterministyczny w replay.
2. **Przeglądarka eskalacjią, nie fetcherem** — `walkRedirects` liczy hop'y;
   przeglądarka followuje je po cichu i zepsułaby ten licznik.
3. **Budżet i jawność** — `WEB_RENDER_MAX` (domyślnie 3) na zapytanie; tryb
   `all` tylko świadomie; błąd przeglądarki nie wywala pipeline'u.
4. **Replay jest czysty** — bez renderera nie ma requestów: ewaluacja offline
   pozostaje deterministyczna, bramka CI nie może „pogięzić" wyniku siecią.

## Sandbox Python (receptury)

```bash
python src/sandbox/launch.py --recipe web_search_brief --args '{"query":"PHP 8.4 release changelog"}'
python src/sandbox/launch.py --recipe web_verify_links  --args '{"urls":["https://www.php.net/releases/8.4/en.php","https://ten-url-nie-istnieje.example"]}'
python src/sandbox/launch.py --recipe web_render_page  --args '{"url":"https://example.com"}'
```

Receptury: `web_search_brief`, `web_verify_links`, `web_drift_report`,
`web_render_page`. Antywzorzec: model pcha **jedno** wywołanie, partia dzieje
się w silniu. Sesje (`--workspace --session ID`) trzymają `WORKSPACE` między
wywołaniami (TTL 15 min, max 50). W repo jest tylko przestrzeń `web` —
reszta sandboxu jest celowo pusta.

## Bramki

```bash
npm run syntax         # node --check + py_compile na wszystkim
npm run test:unit      # browser/render, serwer MCP (ze stubem), HTTP/bridge
npm run test:web       # 49 testów rdzenia (plan/propose/resolve/falsify/cache/feeds/dashboard)
npm run test:py        # 10 testów receptur + 10 testów sesji/launchera (offline)
npm run eval           # ewaluacja replay + gate regresji
npm run eval:live      # to samo z prawdziwą siecią
```

Wynik na dziś: **syntax 0 błędów · 49 + 3 Node · 20 Python · eval gate PASS**.

## Layout

```
src/
  engine/     rdzeń AiSearch (16 modułów) + instance.mjs (wspólna instancja) + dashboard
  browser/    client.mjs (NDJSON MCP → Obscura) · render.mjs (polityka eskalacji)
  mcp/        server.mjs — jeden serwer: web.* + browser_* (zero zależności)
  http/       server.mjs (REST) · bridge.mjs (CLI stdin→stdout)
  sandbox/    client.py · launch.py · tools.py (mock) · sessions.py · redact.py · recipes/
test/         testy Node (stub Obscury w test/stub-obscura.mjs)
fixtures/     web-eval.json — nagrania do deterministycznego replay
scripts/      web-eval.mjs · check-syntax.mjs
bin/          tutaj ląduje obscura.exe (gitignored — pobierz z Releases)
docs/         ARCHITECTURE.md
```

## Wymagania

- Node ≥ 20 (do silnika, MCP, HTTP, testów)
- Python ≥ 3.11 (sandbox + receptury; tylko stdlib)
- Obscura **opcjonalna** — bez niej silnik działa (fetch, SERP, nauka), render
  i `browser_*` są wyłączone. Binaria: GitHub Releases projektu
  [Obscura](https://github.com/h4ckf0r0day/obscura) → `bin/` albo `OBSCURA_BIN`.

## Konfiguracja

Pełna lista z komentarzami: `.env.example` (→ `.env`, nigdy do gita). Najważniejsze:
`WEB_RENDER` (auto/all/off), `WEB_RENDER_MAX`, `WEB_SERP_ENABLED`,
`WEB_COVERAGE_THRESHOLD`, `WEB_CONCURRENCY`, `WEB_HTTP_PORT`, `WEB_API_KEY`.

TDQS

C2.8/5.0

Scored across 13 tools

Disambiguation3/5

Most tools occupy distinct niches (search, render, verify_links, feeds, cache, configure), but web.drift and web.drift_report clearly overlap, and web.stats vs web.trace both expose internal ecosystem state with only subtle wording differences. web.brief vs web.search is also a thin distinction (collapsed output for reports vs full ranked result). Descriptions help, but an agent can plausibly misselect among these pairs.

Naming Consistency4/5

All tools share a clean `web.` namespace with lowercase snake/compound names, which is highly predictable. The minor deviation is mixed grammatical style — some are verbs (search, render, verify_links, configure) and others plain nouns (stats, cache, feeds, drift), plus drift vs drift_report is an inconsistent granularity pair.

Tool Count4/5

13 tools sits comfortably in a well-scoped range and each maps to a recognizable stage of the search/resolve/learn pipeline. It is slightly heavy on introspection tools (stats, trace, cache, configure, eval) relative to the core search surface, but nothing feels gratuitous.

Completeness4/5

The lifecycle is essentially covered end-to-end: search, verify, brief, render, trace, feedback/learning loop, eval, caching, feeds and configuration all have entry points. Minor gaps include no explicit single-URL content extraction distinct from render, and no direct read of a stored linklog/prior record despite feedback writing to it.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues