Skip to main content

g6-knowledge-fetcher

Use when an agent must read a web page or search arXiv, an OAI-PMH repository, OpenAlex or Semantic Scholar, and must know exactly what came back, so a blocked, failed or cut-short fetch is never read as "there is nothing", and fetched text is kept as untrusted data rather than instructions.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 26, 2026 at 01:52
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
g6-knowledge-fetcher
description
Use when an agent must read a web page or search arXiv, an OAI-PMH repository, OpenAlex or Semantic Scholar, and must know exactly what came back, so a blocked, failed or cut-short fetch is never read as "there is nothing", and fetched text is kept as untrusted data rather than instructions.
# G6 knowledge fetcher Fetches a page or a search through G6's checked HTTP and says exactly what happened: what came back, with its source and the hash of the bytes read, or the failure it was. A web page comes back as the text a reader sees. A search keeps the source's own count of matches, so a list cut short says so. ## When to use it - Before an agent answers from a web page or a paper search: fetch it here, so a 403, a timeout or a parse failure is reported as itself rather than as "no results". - To search arXiv (`arxiv`), an OAI-PMH repository (`oai_pmh`), OpenAlex (`openalex`) or Semantic Scholar (`semantic_scholar`) and keep how many matches each reported. - To fetch a PDF or another binary file: it is kept by its hash for `knowledge_converter`. ## When not to use it - For a page behind a login, or one that needs its scripts run: G6 sends no cookies and runs no scripts, so it gets what the server sends a plain client. - For general web search across engines: that is a search stage, not this. - To decide whether what came back is true or current: `g6.grounding` judges claims, `knowledge_manifest` re-checks a cited passage later. ## Ops - `fetch`: a page or a search through G6's checked HTTP (every hop checked, a size cap, a pause per host, robots.txt for pages), with a typed outcome: ok, empty, or the failure it was (refused, robots_disallowed, blocked, not_found, rate_limited, server_error, http_error, too_large, unreachable, parse_failed, rejected). Sensitive. - `sources`: the registered sources, what each needs, the pause it keeps and whether robots.txt applies; nothing is fetched. ## Reading the result `outcome` and its code: - `ok` (`G6_E_KNOWLEDGE_FETCHED`, `qualified-draft`): `documents` holds the text, each with its `source` (the address read after redirects, the SHA-256 of the bytes, when, `fetched`), `media_type`, `title` and `locator` (a paper's own address). An HTML page is the text a reader sees: scripts, styles, templates and hidden elements (`hidden`, `aria-hidden`, an inline `display: none`) are dropped, and how much hidden text there was is listed in the document's `unread`; `noscript` text is kept, elements end where a browser ends them, its `title` is kept apart, and the document says it came from HTML (`media_type` `text/html`, `converted_by` `g6.knowledge html_to_text`). A body that is neither text nor HTML is kept instead: `kept` is its hash and `documents` is empty. - `empty` (`G6_E_KNOWLEDGE_FETCH_EMPTY`, `qualified-draft`): the source answered with nothing, or a page has no text without running its scripts (the reason says which). That is not evidence that nothing exists elsewhere or under another query. - Every failure is `blocked-escalated` with its own code (`G6_E_KNOWLEDGE_FETCH_` and the outcome): `refused` (not a public address), `robots_disallowed` (or its robots.txt could not be read), `blocked` (401, 403, 407, 451), `not_found` (404, 410), `rate_limited` (429), `server_error` (5xx), `http_error` (another error status or too many redirects), `too_large`, `unreachable` (no DNS answer, connection, TLS or a timeout), `parse_failed` (the reply is not the source's format, or lacks a part its API always sends, such as its count of matches) and `rejected` (the source said the request is malformed, or answered with its error object). Only a source's own explicit empty answer is `empty`. `total` is the number of matches the source reported and `complete` whether all came back (`null` for a page). Refusals before anything is sent: `G6_E_KNOWLEDGE_UNKNOWN_SOURCE`, `G6_E_KNOWLEDGE_FETCH_INPUT` (no url or query, or a malformed arXiv category) and `G6_E_KNOWLEDGE_FETCH_ADAPTER` (a source adapter that broke). ## Alone and composed Over MCP, `fetch` runs only when the person who runs the server lists it in `G6_MCP_SENSITIVE`: `g6_invoke("knowledge_fetcher", "fetch", {"source": "arxiv", "query": "grounding", "categories": ["cs.CL"], "max_results": 20})`, or `{"source": "http", "url": "https://..."}`, or `{"source": "oai_pmh", "url": "https://export.arxiv.org/oai2", "set_spec": "cs", "since": "2026-01-01"}`. `openalex` takes `mailto` (its polite pool's contact address), sent only when you give one. From Python: `from g6.knowledge.knowledge_fetcher import FetchRequest, fetch, SOURCES`. `fetch(request)` returns a `FetchResult`; `clients=` passes your own `g6.core.http.Client` per source (tests pass a transport double). Register a source of your own with `SOURCES.register(adapter)`: it reaches the network only through the client it is given, so it gets the same checks. Composed: `knowledge_chunker` cuts a document into passages to cite; `knowledge_converter` turns kept bytes (a PDF) into text; `knowledge_manifest` records passages and later re-checks them against a fresh fetch. ## Failure modes it catches - `failure_read_as_empty` (a failed or blocked search taken to mean there are no results): each HTTP status class, transport error and parse failure is its own outcome and code; only a source that answered with nothing is `empty`. - `incomplete_literature` (conclusions drawn from an incomplete search of the literature): a search keeps the source's own count of matches beside what came back, and says when the list is not the whole of what it holds. - `unreadable_source` (source material skipped or garbled because its format could not be read): a fetched page's HTML is read as the text a reader sees, and a body in another format is kept for `knowledge_converter` rather than passed off as text. ## Blind spots - `prompt_injection`: a fetched page can carry instructions. The text is untrusted data (its `trust` is always `untrusted`), instruction-like phrasing is named on the card, and nothing here acts on it; an agent that reads the text can still be swayed by it. - A login or challenge page served with status 200 comes back as content. - Text hidden by a style sheet rather than an inline style, and text a page's scripts would write, are not seen. - A source's own count can be wrong, and a search can miss what its index does not hold; `complete` speaks only of what that source reported. - Parsers are tested on fixtures of each format, not against the live services. - The documented APIs are governed by their own terms, so robots.txt is read for `http` pages only. ## What it needs Network access to the sources you name; no key, no outside program, no extra. Every request goes through `g6.core.http` (standard library). Kept bytes go to `$G6_HOME/knowledge/fetched/`. No model is called. ## Examples ```g6-example op=sources {} ``` The reply lists `arxiv`, `http`, `oai_pmh`, `openalex` and `semantic_scholar`, with arXiv's three-second pause. ```g6-example op=fetch {"source": "arxiv", "query": "citation grounding", "categories": ["cs.CL"], "max_results": 5} ``` Sensitive: over MCP it runs only when the server's owner allows it. The reply's `total` is arXiv's count of matches. ```python from g6.core import http from g6.knowledge.knowledge_fetcher import FetchRequest, fetch def answers(request): # the network, in this example: no robots.txt, and the page refuses access if request.url.endswith("/robots.txt"): return http.Response(404, {}, b"", request.url) return http.Response(403, {"content-type": "text/html"}, b"<h1>Access denied</h1>", request.url) def clients(adapter): return http.Client(transport=answers, resolver=lambda host, port: ["93.184.216.34"], obey_robots=adapter.obey_robots) found = fetch(FetchRequest(source="http", url="https://example.org/report"), clients=clients) assert found.outcome == "blocked" and found.documents == [] # a 403 is a failure, never an empty page ``` ## The four open problems - **Learning signals**: each reply records the outcome, the status, the address, the pause kept and whether robots.txt applied, per source. Not yet: nothing learns from them. - **Evaluators the model cannot influence**: the outcome is set from the status, the transport's error and the parse in fixed code; no model is called and the page's words cannot change it. - **Transfer by failure mode**: the outcomes are bound to `failure_read_as_empty` and `incomplete_literature` and apply to every source registered, including your own. - **Enough held-out cases**: Not yet: the tests are fixed fixtures and transport doubles; there is no frozen corpus of real 403, redirect and changed-page replies.
View on GitHub