26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
137 lines
5.5 KiB
Markdown
137 lines
5.5 KiB
Markdown
# Journey 17 — Beyond Coding: Web & Research
|
|
|
|
> Not every agent task is code. You want the agent to read a changelog, pull an
|
|
> API spec, summarise an RFC, or extract the claims from a blog post or a video —
|
|
> without pasting raw HTML into the context window. This journey covers
|
|
> `ctx_url_read`: one tool that turns a URL, PDF, or YouTube video into
|
|
> **compressed, citation-backed context**.
|
|
|
|
Source files referenced here:
|
|
- `rust/src/tools/registered/ctx_url_read.rs` — the MCP tool (`CtxUrlReadTool`), arg parsing + clamps
|
|
- `rust/src/core/web/mod.rs` — `read_url`, `ReadMode`, `ReadOptions`, `DEFAULT_MAX_TOKENS`/`DEFAULT_MAX_ITEMS`
|
|
- `rust/src/core/web/url_guard.rs` — SSRF guard (scheme + private/loopback/link-local block)
|
|
- `rust/src/core/web/fetch.rs` — bounded, redirect-revalidated HTTP fetch (`DEFAULT_TIMEOUT_SECS`)
|
|
- `rust/src/core/web/html_to_text.rs` — HTML → clean Markdown
|
|
- `rust/src/core/web/pdf.rs` — remote PDF → text
|
|
- `rust/src/core/web/youtube.rs` — video URL → transcript
|
|
- `rust/src/core/web/distill.rs` — research-compression modes
|
|
- `rust/src/core/web/citation.rs` — source attribution (`Citation`)
|
|
- `rust/src/core/evidence.rs` — `Claim` (confidence + source) for `facts`/`quotes`
|
|
|
|
---
|
|
|
|
## 0. The principle
|
|
|
|
> `ctx_url_read` is the web counterpart of `ctx_read`: one tool call, one token
|
|
> budget, boilerplate stripped, the source preserved for citation. Nothing is
|
|
> fetched unless you pass a URL, and only `http`/`https` URLs that survive the
|
|
> SSRF guard are ever requested.
|
|
|
|
---
|
|
|
|
## 1. The pipeline
|
|
|
|
`read_url` (`core/web/mod.rs`) is the single entry point; the MCP tool is a thin
|
|
wrapper over it. The flow:
|
|
|
|
1. **`url_guard`** validates the URL and blocks SSRF targets.
|
|
2. **`fetch`** downloads it (bounded, manual-redirect, SSRF-revalidated) — or
|
|
**`youtube`** pulls a transcript for video URLs.
|
|
3. **`html_to_text`** renders HTML to clean Markdown (and **`pdf`** converts a
|
|
remote PDF to text).
|
|
4. **`distill`** applies the requested research-compression mode.
|
|
5. **`citation`** attaches source attribution.
|
|
|
|
---
|
|
|
|
## 2. The tool surface
|
|
|
|
`CtxUrlReadTool::handle` (`ctx_url_read.rs`) parses the arguments, clamps them,
|
|
and calls `web::read_url`.
|
|
|
|
| Argument | Type | Default | Clamp | Code |
|
|
|----------|------|---------|-------|------|
|
|
| `url` | string | — (required) | — | `get_str(args, "url")` |
|
|
| `mode` | string | `auto` | enum | `ReadMode::parse` |
|
|
| `query` | string | — | — | `get_str(args, "query")` |
|
|
| `max_tokens` | integer | `6000` | `200..=50_000` | `DEFAULT_MAX_TOKENS` |
|
|
| `max_items` | integer | `12` | `1..=100` | `DEFAULT_MAX_ITEMS` |
|
|
| `timeout_secs` | integer | `20` | `1..=60` | `fetch::DEFAULT_TIMEOUT_SECS` |
|
|
|
|
---
|
|
|
|
## 3. Distillation modes
|
|
|
|
`ReadMode` (`core/web/mod.rs`) selects how fetched content is distilled before it
|
|
is returned. `distill.rs` implements the extractive, relevance-ranked logic.
|
|
|
|
| Mode | What you get | Code path |
|
|
|------|--------------|-----------|
|
|
| `auto` | Markdown for pages, transcript for videos (default) | `ReadMode::Auto` |
|
|
| `markdown` | Clean Markdown of the main content | `html_to_text` |
|
|
| `text` | Plain text (Markdown decorations stripped) | `distill` |
|
|
| `links` | Extracted hyperlinks (max 100) | `MAX_LINKS` |
|
|
| `facts` | Sentences carrying factual signals, as `Claim`s | `distill` + `evidence::Claim` |
|
|
| `quotes` | Central / query-relevant sentences as evidence | `distill` + `evidence::Claim` |
|
|
| `transcript` | De-duplicated, filler-stripped transcript | `youtube` + `transcript_compact` |
|
|
|
|
`mode` parsing accepts a few aliases: `md`→markdown, `plain`→text, `summary`→transcript.
|
|
|
|
```bash
|
|
# Auto mode — Markdown for a page
|
|
ctx_url_read url="https://example.com/post"
|
|
|
|
# A remote PDF as text within a 3000-token budget
|
|
ctx_url_read url="https://example.com/paper.pdf" mode="text" max_tokens=3000
|
|
|
|
# A YouTube transcript
|
|
ctx_url_read url="https://youtu.be/VIDEO" mode="transcript"
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Citations & evidence
|
|
|
|
The `facts` and `quotes` modes do not just summarise: each returned item is a
|
|
`Claim` (`core/evidence.rs`) carrying a **confidence score** and the **source
|
|
URL** it came from (`citation.rs`). That makes web research auditable — the agent
|
|
can attribute every statement, and you can verify it later. A `query` boosts
|
|
relevance so extraction focuses on the part of the page you care about.
|
|
|
|
```bash
|
|
ctx_url_read url="https://example.com/spec" mode="facts" query="rate limits and quotas"
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Research compression
|
|
|
|
A single documentation page can blow a context window. `read_url` distils the
|
|
fetched content down to `max_tokens` (default `DEFAULT_MAX_TOKENS` = 6000) using
|
|
extractive, relevance-ranked compression, and caps `facts`/`quotes` at
|
|
`max_items` (default `DEFAULT_MAX_ITEMS` = 12). The tool then appends the usual
|
|
savings line (`append_savings`) so the token budget is visible.
|
|
|
|
---
|
|
|
|
## 6. Safety — the SSRF guard
|
|
|
|
`url_guard.rs` enforces, before any request and again after each redirect in
|
|
`fetch.rs`:
|
|
|
|
- only `http` / `https` schemes are allowed;
|
|
- requests to **private, loopback and link-local** addresses are blocked.
|
|
|
|
So an agent cannot be steered into probing your internal network. Fetches are
|
|
bounded in size and honour `timeout_secs` (default 20, max 60).
|
|
|
|
---
|
|
|
|
## 7. Where it fits
|
|
|
|
`ctx_url_read` ships with the binary and is registered in
|
|
`rust/src/server/registry.rs`, so it is exposed automatically wherever lean-ctx
|
|
runs as an MCP server — no extra configuration. Pair it with
|
|
`ctx_knowledge` to remember what you learned, and it becomes a durable research
|
|
loop that survives the session.
|