Files
microdao-daarion/docs/cursor/crawl4ai_web_crawler_task.md
Apple 4601c6fca8 feat: add Vision Encoder service + Vision RAG implementation
- Vision Encoder Service (OpenCLIP ViT-L/14, GPU-accelerated)
  - FastAPI app with text/image embedding endpoints (768-dim)
  - Docker support with NVIDIA GPU runtime
  - Port 8001, health checks, model info API

- Qdrant Vector Database integration
  - Port 6333/6334 (HTTP/gRPC)
  - Image embeddings storage (768-dim, Cosine distance)
  - Auto collection creation

- Vision RAG implementation
  - VisionEncoderClient (Python client for API)
  - Image Search module (text-to-image, image-to-image)
  - Vision RAG routing in DAGI Router (mode: image_search)
  - VisionEncoderProvider integration

- Documentation (5000+ lines)
  - SYSTEM-INVENTORY.md - Complete system inventory
  - VISION-ENCODER-STATUS.md - Service status
  - VISION-RAG-IMPLEMENTATION.md - Implementation details
  - vision_encoder_deployment_task.md - Deployment checklist
  - services/vision-encoder/README.md - Deployment guide
  - Updated WARP.md, INFRASTRUCTURE.md, Jupyter Notebook

- Testing
  - test-vision-encoder.sh - Smoke tests (6 tests)
  - Unit tests for client, image search, routing

- Services: 17 total (added Vision Encoder + Qdrant)
- AI Models: 3 (qwen3:8b, OpenCLIP ViT-L/14, BAAI/bge-m3)
- GPU Services: 2 (Vision Encoder, Ollama)
- VRAM Usage: ~10 GB (concurrent)

Status: Production Ready 
2025-11-17 05:24:36 -08:00

380 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Task: Web Crawler Service (crawl4ai) & Agent Tool Integration
## Goal
Інтегрувати **crawl4ai** в агентську систему MicroDAO/DAARION як:
1. Окремий бекенд-сервіс **Web Crawler**, який:
- вміє скрапити сторінки з JS (Playwright/Chromium),
- повертати структурований текст/HTML/метадані,
- (опційно) генерувати події `doc.upserted` для RAG-ingestion.
2. Агентський **tool** `web_crawler`, який викликається через Tool Proxy і доступний агентам (Team Assistant, Bridges Agent, тощо) з урахуванням безпеки.
Мета — дати агентам можливість читати зовнішні веб-ресурси (з обмеженнями) і, за потреби, індексувати їх у RAG.
---
## Context
- Root: `microdao-daarion/`.
- Інфраструктура агентів та tools:
- `docs/cursor/12_agent_runtime_core.md`
- `docs/cursor/13_agent_memory_system.md`
- `docs/cursor/37_agent_tools_and_plugins_specification.md`
- `docs/cursor/20_integrations_bridges_agent.md`
- RAG-шар:
- `docs/cursor/rag_gateway_task.md`
- `docs/cursor/rag_ingestion_worker_task.md`
- `docs/cursor/rag_ingestion_events_wave1_mvp_task.md`
- Event Catalog / NATS:
- `docs/cursor/42_nats_event_streams_and_event_catalog.md`
- `docs/cursor/43_database_events_outbox_design.md`
На сервері вже встановлено `crawl4ai[all]` та `playwright chromium`.
---
## 1. Сервіс Web Crawler
### 1.1. Структура сервісу
Створити новий Python-сервіс (подібно до інших внутрішніх сервісів):
- Директорія: `services/web-crawler/`
- Файли (пропозиція):
- `main.py` — entrypoint (FastAPI/uvicorn).
- `api.py` — визначення HTTP-ендпоїнтів.
- `crawl_client.py` — обгортка над crawl4ai.
- `models.py` — Pydantic-схеми (request/response).
- `config.py` — налаштування (timeouts, max_depth, allowlist доменів, тощо).
Сервіс **не** має прямого UI; його викликають Tool Proxy / інші бекенд-сервіси.
### 1.2. Основний ендпоїнт: `POST /api/web/scrape`
Пропонований контракт:
**Request JSON:**
```json
{
"url": "https://example.com/article",
"team_id": "dao_greenfood",
"session_id": "sess_...",
"max_depth": 1,
"max_pages": 1,
"js_enabled": true,
"timeout_seconds": 30,
"user_agent": "MicroDAO-Crawler/1.0",
"mode": "public",
"indexed": false,
"tags": ["external", "web", "research"],
"return_html": false,
"max_chars": 20000
}
```
**Response JSON (скорочено):**
```json
{
"ok": true,
"url": "https://example.com/article",
"final_url": "https://example.com/article",
"status_code": 200,
"content": {
"text": "... main extracted text ...",
"html": "<html>...</html>",
"title": "Example Article",
"language": "en",
"meta": {
"description": "...",
"keywords": ["..."]
}
},
"links": [
{ "url": "https://example.com/next", "text": "Next" }
],
"raw_size_bytes": 123456,
"fetched_at": "2025-11-17T10:45:00Z"
}
```
Використати API/параметри crawl4ai для:
- рендеру JS (Playwright),
- витягання основного контенту (article/reader mode, якщо є),
- нормалізації тексту (видалення зайвого boilerplate).
### 1.3. Додаткові ендпоїнти (опційно)
- `POST /api/web/scrape_batch` — масовий скрап кількох URL (обмежений top-K).
- `POST /api/web/crawl_site` — обхід сайту з `max_depth`/`max_pages` (для MVP можна не реалізовувати або залишити TODO).
- `POST /api/web/scrape_and_ingest` — варіант, який одразу шле подію `doc.upserted` (див. розділ 3).
### 1.4. Обмеження та безпека
У `config.py` передбачити:
- `MAX_DEPTH` (наприклад, 12 для MVP).
- `MAX_PAGES` (наприклад, 35).
- `MAX_CHARS`/`MAX_BYTES` (щоб не забивати памʼять).
- (Опційно) allowlist/denylist доменів для кожної команди/DAO.
- таймаут HTTP/JS-запиту.
Логувати тільки мінімальний технічний контекст (URL, код статусу, тривалість), **не** зберігати повний HTML у логах.
---
## 2. Обгортка над crawl4ai (`crawl_client.py`)
Створити модуль, який інкапсулює виклики crawl4ai, щоб API/деталі можна було змінювати централізовано.
Приблизна логіка:
- функція `async def fetch_page(url: str, options: CrawlOptions) -> CrawlResult`:
- налаштувати crawl4ai з Playwright (chromium),
- виконати рендер/збір контенту,
- повернути нормалізований результат: text, html (опційно), метадані, посилання.
Обовʼязково:
- коректно обробляти помилки мережі, редіректи, 4xx/5xx;
- повертати `ok=false` + error message у HTTP-відповіді API.
---
## 3. Інтеграція з RAG-ingestion (doc.upserted)
### 3.1. Подія `doc.upserted` для веб-сторінок
Після успішного скрапу, якщо `indexed=true`, Web Crawler може (в майбутньому або одразу) створювати подію:
- `event`: `doc.upserted`
- `stream`: `STREAM_PROJECT` або спеціальний `STREAM_DOCS`
Payload (адаптований під RAG-дизайн):
```json
{
"doc_id": "web::<hash_of_url>",
"team_id": "dao_greenfood",
"project_id": null,
"path": "web/https_example_com_article",
"title": "Example Article",
"text": "... main extracted text ...",
"url": "https://example.com/article",
"tags": ["web", "external", "research"],
"visibility": "public",
"doc_type": "web",
"indexed": true,
"mode": "public",
"updated_at": "2025-11-17T10:45:00Z"
}
```
Цю подію можна:
1. заповнити в таблицю outbox (див. `43_database_events_outbox_design.md`),
2. з неї Outbox Worker відправить у NATS (JetStream),
3. `rag-ingest-worker` (згідно `rag_ingestion_events_wave1_mvp_task.md`) сприйме `doc.upserted` і проіндексує сторінку в Milvus/Neo4j.
### 3.2. Підтримка у нормалізаторі
У `services/rag-ingest-worker/pipeline/normalization.py` уже є/буде `normalize_doc_upserted`:
- для веб-сторінок `doc_type="web"` потрібно лише переконатися, що:
- `source_type = "doc"` або `"web"` (на твій вибір, але консистентний),
- у `tags` включено `"web"`/`"external"`,
- у metadata є `url`.
Якщо потрібно, можна додати просту гілку для `doc_type == "web"`.
---
## 4. Agent Tool: `web_crawler`
### 4.1. Категорія безпеки
Відповідно до `37_agent_tools_and_plugins_specification.md`:
- Зовнішній інтернет — **Category D — Critical Tools** (`browser-full`, `external_api`).
- Новий інструмент:
- назва: `web_crawler`,
- capability: `tool.web_crawler.invoke`,
- категорія: **D (Critical)**,
- за замовчуванням **вимкнений** — вмикається Governance/адміністратором для конкретних MicroDAO.
### 4.2. Tool request/response контракт
Tool Proxy викликає Web Crawler через HTTP.
**Request від Agent Runtime до Tool Proxy:**
```json
{
"tool": "web_crawler",
"args": {
"url": "https://example.com/article",
"max_chars": 8000,
"indexed": false,
"mode": "public"
},
"context": {
"agent_run_id": "ar_123",
"team_id": "dao_greenfood",
"user_id": "u_001",
"channel_id": "ch_abc"
}
}
```
Tool Proxy далі робить HTTP-запит до `web-crawler` сервісу (`POST /api/web/scrape`).
**Відповідь до агента (спрощена):**
```json
{
"ok": true,
"output": {
"title": "Example Article",
"url": "https://example.com/article",
"snippet": "Короткий уривок тексту...",
"full_text": "... обрізаний до max_chars ..."
}
}
```
Для безпеки:
- у відповідь, яку бачить LLM/агент, повертати **обмежений** `full_text` (наприклад, 810k символів),
- якщо `full_text` занадто довгий — обрізати та явно це позначити.
### 4.3. PDP та quotas
- Перед викликом Tool Proxy повинен викликати PDP:
- `action = tool.web_crawler.invoke`,
- `subject = agent_id`,
- `resource = team_id`.
- Usage Service (див. 44_usage_accounting_and_quota_engine.md) може:
- рахувати кількість викликів `web_crawler`/день,
- обмежувати тривалість/обʼєм даних.
---
## 5. Інтеграція з Bridges Agent / іншими агентами
### 5.1. Bridges Agent
Bridges Agent (`20_integrations_bridges_agent.md`) може використовувати `web_crawler` як один зі своїх tools:
- сценарій: "Підтяни останню версію документації з https://docs.example.com/... і збережи як doc у Co-Memory";
- Bridges Agent викликає tool `web_crawler`, отримує текст, створює внутрішній doc (через Projects/Co-Memory API) і генерує `doc.upserted`.
### 5.2. Team Assistant / Research-агенти
Для окремих DAO можна дозволити:
- `Team Assistant` викликає `web_crawler` для досліджень (наприклад, "знайди інформацію на сайті Мінекономіки про гранти"),
- але з жорсткими лімітами (whitelist доменів, rate limits).
---
## 6. Confidential mode та privacy
Згідно з `47_messaging_channels_and_privacy_layers.md` та `48_teams_access_control_and_confidential_mode.md`:
- Якщо контекст агента `mode = confidential`:
- інструмент `web_crawler` **не повинен** отримувати confidential plaintext із внутрішніх повідомлень (тобто, у `args` не має бути фрагментів внутрішнього тексту);
- зазвичай достатньо лише URL.
- Якщо `indexed=true` та `mode=confidential` для веб-сторінки (рідкісний кейс):
- можна дозволити зберігати plaintext сторінки в RAG, оскільки це зовнішнє джерело;
- але варто позначати таку інформацію як `source_type="web_external"` і у PDP контролювати, хто може її читати.
Для MVP в цій задачі достатньо:
- заборонити виклик `web_crawler` із confidential-контексту без явної конфігурації (тобто PDP повертає deny).
---
## 7. Логування та моніторинг
Додати базове логування в Web Crawler:
- при кожному скрапі:
- `team_id`,
- `url`,
- `status_code`,
- `duration_ms`,
- `bytes_downloaded`.
Без збереження body/HTML у логах.
За бажанням — контрприклад метрик:
- `web_crawler_requests_total`,
- `web_crawler_errors_total`,
- `web_crawler_avg_duration_ms`.
---
## 8. Files to create/modify (suggested)
> Назви/шляхи можна адаптувати до фактичної структури, важлива ідея.
- `services/web-crawler/main.py`
- `services/web-crawler/api.py`
- `services/web-crawler/crawl_client.py`
- `services/web-crawler/models.py`
- `services/web-crawler/config.py`
- Tool Proxy / агентський runtime (Node/TS):
- додати tool `web_crawler` у список інструментів (див. `37_agent_tools_and_plugins_specification.md`).
- оновити Tool Proxy, щоб він міг робити HTTP-виклик до Web Crawler.
- Bridges/Team Assistant агенти:
- (опційно) додати `web_crawler` у їхні конфіги як доступний tool.
- RAG ingestion:
- (опційно) оновити `rag-ingest-worker`/docs, щоб описати `doc_type="web"` у `doc.upserted` подіях.
---
## 9. Acceptance criteria
1. Існує новий сервіс `web-crawler` з ендпоїнтом `POST /api/web/scrape`, який використовує crawl4ai+Playwright для скрапу сторінок.
2. Ендпоїнт повертає текст/метадані у структурованому JSON, з обмеженнями по розміру.
3. Заготовлена (або реалізована) інтеграція з Event Catalog через подію `doc.upserted` для `doc_type="web"` (indexed=true).
4. У Tool Proxy зʼявився tool `web_crawler` (категорія D, capability `tool.web_crawler.invoke`) з чітким request/response контрактом.
5. PDP/usage engine враховують новий tool (принаймні у вигляді basic перевірок/квот).
6. Bridges Agent (або Team Assistant) може використати `web_crawler` для простого MVP-сценарію (наприклад: скрапнути одну сторінку і показати її summary користувачу).
7. Конфіденційний режим враховано: у конфігурації за замовчуванням `web_crawler` недоступний у `confidential` каналах/командах.
---
## 10. Інструкція для Cursor
```text
You are a senior backend engineer (Python + Node/TS) working on the DAARION/MicroDAO stack.
Implement the Web Crawler service and agent tool integration using:
- crawl4ai_web_crawler_task.md
- 37_agent_tools_and_plugins_specification.md
- 20_integrations_bridges_agent.md
- rag_gateway_task.md
- rag_ingestion_worker_task.md
- 42_nats_event_streams_and_event_catalog.md
Tasks:
1) Create the `services/web-crawler` service (FastAPI or equivalent) with /api/web/scrape based on crawl4ai.
2) Implement basic options: js_enabled, max_depth, max_pages, max_chars, timeouts.
3) Add tool `web_crawler` to the Tool Proxy (category D, capability tool.web_crawler.invoke).
4) Wire Tool Proxy → Web Crawler HTTP call with proper request/response mapping.
5) (Optional but preferred) Implement doc.upserted emission for indexed=true pages (doc_type="web") via the existing outbox → NATS flow.
6) Add a simple usage example in Bridges Agent or Team Assistant config (one agent that can use this tool in dev).
Output:
- list of modified files
- diff
- summary
```